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,7 +73,7 @@ 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)
} }
} }
} }
@ -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,11 +190,10 @@ 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():
@ -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()])
} }
@ -240,4 +239,3 @@ func eventLoop() {
} }
} }
} }

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

53
main.go
View File

@ -1,4 +1,4 @@
package gpass package passgo
import ( import (
"bufio" "bufio"
@ -40,9 +40,9 @@ func GetStore() (*Store, error) {
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")
@ -69,13 +69,13 @@ type Pass struct {
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
} }