Rename to passgo and run go fmt.

This commit is contained in:
Greg 2019-09-05 06:41:39 -04:00
parent fc7a4c272e
commit 28ccd6d107
8 changed files with 135 additions and 138 deletions

4
.gitignore vendored
View File

@ -1,2 +1,2 @@
cmd/gpass/gpass cmd/gpass/passgo
cmd/gpass-gui/gpass-gui cmd/gpass-gui/passgo-gui

View File

@ -1,4 +1,4 @@
# gpass # passgo
This repository includes Go code to interact with pass, the Unix password This repository includes Go code to interact with pass, the Unix password
manager. Library code is provided to open a password store, list manager. Library code is provided to open a password store, list
@ -7,7 +7,7 @@ a simple passphrase input function, or, if gpg-agent is running (on MacOS),
it will connect automatically to request your GPG passphrase. it will connect automatically to request your GPG passphrase.
```go ```go
store, err := gpass.GetStore() store, err := passgo.GetStore()
if err != nil { ... } if err != nil { ... }
passlist := store.List() passlist := store.List()
//storeDir := store.Dir //storeDir := store.Dir
@ -15,7 +15,7 @@ for _,x := range passlist {
if x.Pathname = "myPass" { if x.Pathname = "myPass" {
p, err := store.Decrypt(x.Pathname) p, err := store.Decrypt(x.Pathname)
if err == nil { if err == nil {
gpass.Clip(p) // put on the clipboard passgo.Clip(p) // put on the clipboard
} else { } else {
log.Fatal("Cannot decrypt ", x.Pathname) log.Fatal("Cannot decrypt ", x.Pathname)
} }

View File

@ -1,28 +0,0 @@
package main
import (
golog "log"
"os"
)
type logLevelT int
const (
Fatal logLevelT = 1 << iota
Error
Warn
Info
Debug
DebugGfx
)
var loglevel = Fatal | Error | Warn | Info
func log(level logLevelT, msg ...interface{}) {
if level & loglevel != 0 {
golog.Print(msg...)
}
if level & Fatal != 0 {
os.Exit(-1)
}
}

28
cmd/passgo-gui/log.go Normal file
View File

@ -0,0 +1,28 @@
package main
import (
golog "log"
"os"
)
type logLevelT int
const (
Fatal logLevelT = 1 << iota
Error
Warn
Info
Debug
DebugGfx
)
var loglevel = Fatal | Error | Warn | Info
func log(level logLevelT, msg ...interface{}) {
if level&loglevel != 0 {
golog.Print(msg...)
}
if level&Fatal != 0 {
os.Exit(-1)
}
}

View File

@ -4,56 +4,55 @@ package main
import ( import (
//"fmt" //"fmt"
"path"
"strings"
"image" "image"
"image/color" "image/color"
"path"
"strings"
"sync" "sync"
"gioui.org/ui" "gioui.org/ui"
"gioui.org/ui/app" "gioui.org/ui/app"
"gioui.org/ui/f32"
"gioui.org/ui/gesture"
"gioui.org/ui/input" "gioui.org/ui/input"
"gioui.org/ui/key" "gioui.org/ui/key"
"gioui.org/ui/layout" "gioui.org/ui/layout"
"gioui.org/ui/text"
"gioui.org/ui/measure" "gioui.org/ui/measure"
"gioui.org/ui/f32"
"gioui.org/ui/paint" "gioui.org/ui/paint"
"gioui.org/ui/gesture"
"gioui.org/ui/pointer" "gioui.org/ui/pointer"
"gioui.org/ui/text"
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
"golang.org/x/image/font/gofont/goregular" "golang.org/x/image/font/gofont/goregular"
"golang.org/x/image/font/sfnt" "golang.org/x/image/font/sfnt"
"git.wow.st/gmp/passgo"
"git.wow.st/gmp/gpass"
) )
func main() { func main() {
var err error var err error
store,err = gpass.GetStore() store, err = passgo.GetStore()
if err != nil { if err != nil {
log(Fatal, err) log(Fatal, err)
} }
updated = make(chan struct{}) updated = make(chan struct{})
go Updater() go Updater()
log(Info,"Staring event loop") log(Info, "Staring event loop")
go eventLoop() go eventLoop()
app.Main() app.Main()
log(Info,"Event loop returned") log(Info, "Event loop returned")
} }
var ( var (
l []gpass.Pass l []passgo.Pass
mux sync.Mutex mux sync.Mutex
store *gpass.Store store *passgo.Store
updated chan struct{} updated chan struct{}
) )
func Updater() { func Updater() {
update := func() { update := func() {
ltmp,err := store.List() ltmp, err := store.List()
if err != nil { if err != nil {
log(Fatal, err) log(Fatal, err)
} }
@ -74,16 +73,16 @@ func Updater() {
case <-watcher.Events: case <-watcher.Events:
update() update()
case e := <-watcher.Errors: case e := <-watcher.Errors:
log(Info, "Watcher error: ",e) log(Info, "Watcher error: ", e)
} }
} }
} }
type Button struct { type Button struct {
Face text.Face Face text.Face
Label string Label string
Click gesture.Click Click gesture.Click
Color color.RGBA Color color.RGBA
clicked bool clicked bool
} }
@ -114,7 +113,6 @@ func rrect(ops *ui.Ops, width, height, se, sw, nw, ne float32) {
b.End() b.End()
} }
func (b *Button) Layout(c ui.Config, ops *ui.Ops, q input.Queue, cs layout.Constraints) layout.Dimensions { func (b *Button) Layout(c ui.Config, ops *ui.Ops, q input.Queue, cs layout.Constraints) layout.Dimensions {
b.clicked = false b.clicked = false
for ev, ok := b.Click.Next(q); ok; ev, ok = b.Click.Next(q) { for ev, ok := b.Click.Next(q); ok; ev, ok = b.Click.Next(q) {
@ -165,23 +163,25 @@ func eventLoop() {
passInput.SetText("passphrase") passInput.SetText("passphrase")
passSubmit := &Button{Face: face, Label: "submit"} passSubmit := &Button{Face: face, Label: "submit"}
lst := &layout.List{Axis: layout.Vertical} lst := &layout.List{Axis: layout.Vertical}
passBtns := make([]*Button,0) passBtns := make([]*Button, 0)
_ = passInput _ = passInput
_ = passSubmit _ = passSubmit
pathnames := make([]string,0) pathnames := make([]string, 0)
updateBtns := func() { updateBtns := func() {
passBtns = passBtns[:0] passBtns = passBtns[:0]
pathnames = pathnames[:0] pathnames = pathnames[:0]
mux.Lock() mux.Lock()
for _,x := range l { for _, x := range l {
_, n := path.Split(x.Pathname) _, n := path.Split(x.Pathname)
s := strings.Repeat(" /",x.Level) s := strings.Repeat(" /", x.Level)
z := "" z := ""
if x.Dir { z = "/" } if x.Dir {
passBtns = append(passBtns,&Button{ z = "/"
Face:face, }
Label:strings.Join([]string{s,n,z},""), passBtns = append(passBtns, &Button{
Face: face,
Label: strings.Join([]string{s, n, z}, ""),
Color: color.RGBA{A: 0xff, R: 0xf0, G: 0xf0, B: 0xf0}, Color: color.RGBA{A: 0xff, R: 0xf0, G: 0xf0, B: 0xf0},
}) })
pathnames = append(pathnames, x.Pathname) pathnames = append(pathnames, x.Pathname)
@ -190,21 +190,20 @@ func eventLoop() {
} }
updateBtns() updateBtns()
for {
for { select {
select { case <-updated:
case <-updated: log(Info, "UPDATE")
log(Info,"UPDATE")
updateBtns() updateBtns()
w.Invalidate() w.Invalidate()
case e := <-w.Events(): case e := <-w.Events():
switch e := e.(type) { switch e := e.(type) {
case app.DestroyEvent: case app.DestroyEvent:
return return
case app.UpdateEvent: case app.UpdateEvent:
c := &e.Config c := &e.Config
ops.Reset() ops.Reset()
faces.Reset(c) faces.Reset(c)
var dims layout.Dimensions var dims layout.Dimensions
cs := layout.RigidConstraints(e.Size) cs := layout.RigidConstraints(e.Size)
cs = margin.Begin(c, ops, cs) cs = margin.Begin(c, ops, cs)
@ -219,15 +218,15 @@ func eventLoop() {
lst.End(dims) lst.End(dims)
if btn.Clicked() { if btn.Clicked() {
// don't block UI thread on decryption attempt // don't block UI thread on decryption attempt
log(Info,"Clicked ", btn.Label) log(Info, "Clicked ", btn.Label)
go func(name string) { go func(name string) {
//p,err := store.Decrypt(name, prompt) //p,err := store.Decrypt(name, prompt)
p,err := store.Decrypt(name) p, err := store.Decrypt(name)
if err == nil { if err == nil {
gpass.Clip(p) passgo.Clip(p)
} else { } else {
log(Info,"Can't decrypt ", name) log(Info, "Can't decrypt ", name)
log(Info,err) log(Info, err)
} }
}(pathnames[lst.Index()]) }(pathnames[lst.Index()])
} }
@ -235,9 +234,8 @@ func eventLoop() {
mux.Unlock() mux.Unlock()
dims = lst.Layout() dims = lst.Layout()
dims = margin.End(dims) dims = margin.End(dims)
w.Update(ops) w.Update(ops)
} }
} }
} }
} }

View File

@ -6,11 +6,11 @@ import (
"path" "path"
"strings" "strings"
"git.wow.st/gmp/gpass" "git.wow.st/gmp/passgo"
) )
func usage() { func usage() {
fmt.Println("gpass [-c|--clip] [name]") fmt.Println("passgo [-c|--clip] [name]")
os.Exit(-1) os.Exit(-1)
} }
@ -18,53 +18,55 @@ type options struct {
clip bool clip bool
} }
func parse(args []string) ([]string,options) { func parse(args []string) ([]string, options) {
ret := make([]string,0) ret := make([]string, 0)
opts := options{} opts := options{}
for _,a := range args { for _, a := range args {
switch { switch {
case a == "-c",a == "--clip": case a == "-c", a == "--clip":
opts.clip = true opts.clip = true
case a[0] == '-': case a[0] == '-':
usage() usage()
default: default:
ret = append(ret,a) ret = append(ret, a)
} }
} }
return ret,opts return ret, opts
} }
func main() { func main() {
store,err := gpass.GetStore() store, err := passgo.GetStore()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(-1) os.Exit(-1)
} }
args := os.Args[1:] args := os.Args[1:]
args,opts := parse(args) args, opts := parse(args)
switch len(args) { switch len(args) {
case 0: case 0:
l,err := store.List() l, err := store.List()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(-1) os.Exit(-1)
} }
for _, x := range l { for _, x := range l {
_, n := path.Split(x.Pathname) _, n := path.Split(x.Pathname)
s := strings.Repeat(" /",x.Level) s := strings.Repeat(" /", x.Level)
z := "" z := ""
if x.Dir { z = "/" } if x.Dir {
fmt.Println(strings.Join([]string{s,n,z},"")) z = "/"
}
fmt.Println(strings.Join([]string{s, n, z}, ""))
} }
case 1: case 1:
p,err := store.Decrypt(args[0]) p, err := store.Decrypt(args[0])
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(-1) os.Exit(-1)
} }
if opts.clip { if opts.clip {
gpass.Clip(p) passgo.Clip(p)
} else { } else {
fmt.Print(p) fmt.Print(p)
} }
@ -72,4 +74,3 @@ func main() {
usage() usage()
} }
} }

View File

@ -1,11 +1,11 @@
//+build !android !linux //+build !android !linux
package gpass package passgo
import ( import (
"fmt"
"bufio" "bufio"
"bytes" "bytes"
"fmt"
"os" "os"
"os/exec" "os/exec"
"os/user" "os/user"
@ -73,7 +73,7 @@ func setAgentInfo() {
} }
s := fmt.Sprintf("%s:%d:1", filename, pid) s := fmt.Sprintf("%s:%d:1", filename, pid)
fmt.Printf("GPG_AGENT_INFO = %s\n", s) fmt.Printf("GPG_AGENT_INFO = %s\n", s)
os.Setenv("GPG_AGENT_INFO",s) os.Setenv("GPG_AGENT_INFO", s)
// gpg-agent is running, so use GPGPrompt as password prompt // gpg-agent is running, so use GPGPrompt as password prompt
ask = GPGPrompt ask = GPGPrompt
@ -90,4 +90,3 @@ func Clip(x string) {
cmd.Stdin = b cmd.Stdin = b
cmd.Run() cmd.Run()
} }

75
main.go
View File

@ -1,4 +1,4 @@
package gpass package passgo
import ( import (
"bufio" "bufio"
@ -22,7 +22,7 @@ import (
var ( var (
basename *regexp.Regexp basename *regexp.Regexp
ask openpgp.PromptFunction ask openpgp.PromptFunction
) )
func init() { func init() {
@ -30,19 +30,19 @@ func init() {
} }
type Store struct { type Store struct {
Dir string Dir string
keyring openpgp.KeyRing keyring openpgp.KeyRing
} }
func GetStore() (*Store, error) { func GetStore() (*Store, error) {
ret := &Store{} ret := &Store{}
u, err := user.Current() u, err := user.Current()
if err != nil { if err != nil {
return ret, fmt.Errorf("Can't get current user.") return ret, fmt.Errorf("Can't get current user.")
} }
ret.Dir = path.Join(u.HomeDir,".password-store") ret.Dir = path.Join(u.HomeDir, ".password-store")
fd, err := os.Open(path.Join(u.HomeDir,".gnupg/secring.gpg")) fd, err := os.Open(path.Join(u.HomeDir, ".gnupg/secring.gpg"))
defer fd.Close() defer fd.Close()
if err != nil { if err != nil {
return ret, fmt.Errorf("Can't open keyring file") return ret, fmt.Errorf("Can't open keyring file")
@ -52,30 +52,30 @@ func GetStore() (*Store, error) {
return ret, fmt.Errorf("Can't open gnupg keyring.") return ret, fmt.Errorf("Can't open gnupg keyring.")
} }
ret.keyring = kr ret.keyring = kr
return ret, nil return ret, nil
} }
type caseInsensitive []os.FileInfo type caseInsensitive []os.FileInfo
func (fs caseInsensitive) Len() int { return len(fs) } func (fs caseInsensitive) Len() int { return len(fs) }
func (fs caseInsensitive) Swap(i, j int) { fs[i], fs[j] = fs[j], fs[i] } func (fs caseInsensitive) Swap(i, j int) { fs[i], fs[j] = fs[j], fs[i] }
func (fs caseInsensitive) Less(i, j int) bool { func (fs caseInsensitive) Less(i, j int) bool {
return strings.ToLower(fs[i].Name()) < strings.ToLower(fs[j].Name()) return strings.ToLower(fs[i].Name()) < strings.ToLower(fs[j].Name())
} }
type Pass struct { type Pass struct {
Pathname string Pathname string
Level int Level int
Dir bool Dir bool
} }
func (s *Store) List() ([]Pass,error) { func (s *Store) List() ([]Pass, error) {
return s.list(0,"") return s.list(0, "")
} }
func (s *Store) list(level int, p string) ([]Pass,error) { func (s *Store) list(level int, p string) ([]Pass, error) {
ret := make([]Pass,0) ret := make([]Pass, 0)
dir := path.Join(s.Dir,p) dir := path.Join(s.Dir, p)
fd, err := os.Open(dir) fd, err := os.Open(dir)
defer fd.Close() defer fd.Close()
if err != nil { if err != nil {
@ -87,25 +87,25 @@ func (s *Store) list(level int, p string) ([]Pass,error) {
} }
sort.Sort(caseInsensitive(files)) sort.Sort(caseInsensitive(files))
for _, x := range files { for _, x := range files {
n := basename.ReplaceAllLiteralString(x.Name(),"") n := basename.ReplaceAllLiteralString(x.Name(), "")
entry := Pass{Pathname: path.Join(p,n),Level: level} entry := Pass{Pathname: path.Join(p, n), Level: level}
if n[0] == '.' { if n[0] == '.' {
continue continue
} }
if x.IsDir() { if x.IsDir() {
entry.Dir = true entry.Dir = true
ret = append(ret,entry) ret = append(ret, entry)
l,err := s.list(level+1,path.Join(p,x.Name())) l, err := s.list(level+1, path.Join(p, x.Name()))
if err != nil { if err != nil {
return nil,err return nil, err
} }
ret = append(ret,l...) ret = append(ret, l...)
} else { } else {
ret = append(ret,entry) ret = append(ret, entry)
} }
} }
return ret,nil return ret, nil
} }
func AskPass(prompts ...func() []byte) openpgp.PromptFunction { func AskPass(prompts ...func() []byte) openpgp.PromptFunction {
@ -124,7 +124,7 @@ func AskPass(prompts ...func() []byte) openpgp.PromptFunction {
var err error var err error
var passphrase []byte var passphrase []byte
dec := func(p *packet.PrivateKey) { dec := func(p *packet.PrivateKey) {
for i := 0; i<3; i++ { for i := 0; i < 3; i++ {
if err = p.Decrypt(passphrase); err == nil { if err = p.Decrypt(passphrase); err == nil {
break break
} }
@ -135,7 +135,7 @@ func AskPass(prompts ...func() []byte) openpgp.PromptFunction {
var ret openpgp.PromptFunction var ret openpgp.PromptFunction
ret = func(keys []openpgp.Key, symmetric bool) ([]byte, error) { ret = func(keys []openpgp.Key, symmetric bool) ([]byte, error) {
if !symmetric { if !symmetric {
for _,k := range keys { for _, k := range keys {
if p := k.PrivateKey; p != nil && p.Encrypted { if p := k.PrivateKey; p != nil && p.Encrypted {
dec(p) dec(p)
} }
@ -175,18 +175,18 @@ func GPGPrompt(keys []openpgp.Key, symmetric bool) ([]byte, error) {
return nil, fmt.Errorf("Unable to find key") return nil, fmt.Errorf("Unable to find key")
} }
func (s *Store) Decrypt(name string, prompts ...func() []byte) (string,error) { func (s *Store) Decrypt(name string, prompts ...func() []byte) (string, error) {
if ask == nil { if ask == nil {
ask = AskPass(prompts...) ask = AskPass(prompts...)
} }
file := path.Join(s.Dir, strings.Join([]string{name,".gpg"},"")) file := path.Join(s.Dir, strings.Join([]string{name, ".gpg"}, ""))
if _, err := os.Stat(file); os.IsNotExist(err) { if _, err := os.Stat(file); os.IsNotExist(err) {
return "",fmt.Errorf("Not in password store.") return "", fmt.Errorf("Not in password store.")
} }
fd, err := os.Open(file) fd, err := os.Open(file)
defer fd.Close() defer fd.Close()
if err != nil { if err != nil {
return "",err return "", err
} }
var reader io.Reader var reader io.Reader
unarmor, err := armor.Decode(fd) unarmor, err := armor.Decode(fd)
@ -197,19 +197,18 @@ func (s *Store) Decrypt(name string, prompts ...func() []byte) (string,error) {
fd, err = os.Open(file) fd, err = os.Open(file)
defer fd.Close() defer fd.Close()
if err != nil { if err != nil {
return "",err return "", err
} }
reader = fd reader = fd
} }
md, err := openpgp.ReadMessage(reader,s.keyring,ask,nil) md, err := openpgp.ReadMessage(reader, s.keyring, ask, nil)
if err != nil { if err != nil {
fmt.Println("Error reading message") fmt.Println("Error reading message")
return "",err return "", err
} }
ra, err := ioutil.ReadAll(md.UnverifiedBody) ra, err := ioutil.ReadAll(md.UnverifiedBody)
if err != nil { if err != nil {
return "",err return "", err
} }
return string(ra), nil return string(ra), nil
} }