Rename to passgo and run go fmt.
This commit is contained in:
parent
fc7a4c272e
commit
28ccd6d107
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,2 +1,2 @@
|
|||
cmd/gpass/gpass
|
||||
cmd/gpass-gui/gpass-gui
|
||||
cmd/gpass/passgo
|
||||
cmd/gpass-gui/passgo-gui
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# gpass
|
||||
# passgo
|
||||
|
||||
This repository includes Go code to interact with pass, the Unix password
|
||||
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.
|
||||
|
||||
```go
|
||||
store, err := gpass.GetStore()
|
||||
store, err := passgo.GetStore()
|
||||
if err != nil { ... }
|
||||
passlist := store.List()
|
||||
//storeDir := store.Dir
|
||||
|
@ -15,7 +15,7 @@ for _,x := range passlist {
|
|||
if x.Pathname = "myPass" {
|
||||
p, err := store.Decrypt(x.Pathname)
|
||||
if err == nil {
|
||||
gpass.Clip(p) // put on the clipboard
|
||||
passgo.Clip(p) // put on the clipboard
|
||||
} else {
|
||||
log.Fatal("Cannot decrypt ", x.Pathname)
|
||||
}
|
||||
|
|
|
@ -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
28
cmd/passgo-gui/log.go
Normal 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)
|
||||
}
|
||||
}
|
|
@ -4,56 +4,55 @@ package main
|
|||
|
||||
import (
|
||||
//"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
"image"
|
||||
"image/color"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"gioui.org/ui"
|
||||
"gioui.org/ui/app"
|
||||
"gioui.org/ui/f32"
|
||||
"gioui.org/ui/gesture"
|
||||
"gioui.org/ui/input"
|
||||
"gioui.org/ui/key"
|
||||
"gioui.org/ui/layout"
|
||||
"gioui.org/ui/text"
|
||||
"gioui.org/ui/measure"
|
||||
"gioui.org/ui/f32"
|
||||
"gioui.org/ui/paint"
|
||||
"gioui.org/ui/gesture"
|
||||
"gioui.org/ui/pointer"
|
||||
"gioui.org/ui/text"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"golang.org/x/image/font/gofont/goregular"
|
||||
"golang.org/x/image/font/sfnt"
|
||||
|
||||
|
||||
"git.wow.st/gmp/gpass"
|
||||
"git.wow.st/gmp/passgo"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
store,err = gpass.GetStore()
|
||||
store, err = passgo.GetStore()
|
||||
if err != nil {
|
||||
log(Fatal, err)
|
||||
}
|
||||
updated = make(chan struct{})
|
||||
go Updater()
|
||||
log(Info,"Staring event loop")
|
||||
log(Info, "Staring event loop")
|
||||
go eventLoop()
|
||||
app.Main()
|
||||
log(Info,"Event loop returned")
|
||||
log(Info, "Event loop returned")
|
||||
}
|
||||
|
||||
var (
|
||||
l []gpass.Pass
|
||||
mux sync.Mutex
|
||||
store *gpass.Store
|
||||
l []passgo.Pass
|
||||
mux sync.Mutex
|
||||
store *passgo.Store
|
||||
updated chan struct{}
|
||||
)
|
||||
|
||||
func Updater() {
|
||||
update := func() {
|
||||
ltmp,err := store.List()
|
||||
ltmp, err := store.List()
|
||||
if err != nil {
|
||||
log(Fatal, err)
|
||||
}
|
||||
|
@ -74,16 +73,16 @@ func Updater() {
|
|||
case <-watcher.Events:
|
||||
update()
|
||||
case e := <-watcher.Errors:
|
||||
log(Info, "Watcher error: ",e)
|
||||
log(Info, "Watcher error: ", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Button struct {
|
||||
Face text.Face
|
||||
Label string
|
||||
Click gesture.Click
|
||||
Color color.RGBA
|
||||
Face text.Face
|
||||
Label string
|
||||
Click gesture.Click
|
||||
Color color.RGBA
|
||||
clicked bool
|
||||
}
|
||||
|
||||
|
@ -114,7 +113,6 @@ func rrect(ops *ui.Ops, width, height, se, sw, nw, ne float32) {
|
|||
b.End()
|
||||
}
|
||||
|
||||
|
||||
func (b *Button) Layout(c ui.Config, ops *ui.Ops, q input.Queue, cs layout.Constraints) layout.Dimensions {
|
||||
b.clicked = false
|
||||
for ev, ok := b.Click.Next(q); ok; ev, ok = b.Click.Next(q) {
|
||||
|
@ -142,7 +140,7 @@ func (b *Button) Layout(c ui.Config, ops *ui.Ops, q input.Queue, cs layout.Const
|
|||
c1 := st.End(layoutRRect(b.Color, c, ops, st.Expand()))
|
||||
dims = st.Layout(c1, c2)
|
||||
return ins.End(dims)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Button) Clicked() bool {
|
||||
return b.clicked
|
||||
|
@ -165,23 +163,25 @@ func eventLoop() {
|
|||
passInput.SetText("passphrase")
|
||||
passSubmit := &Button{Face: face, Label: "submit"}
|
||||
lst := &layout.List{Axis: layout.Vertical}
|
||||
passBtns := make([]*Button,0)
|
||||
passBtns := make([]*Button, 0)
|
||||
_ = passInput
|
||||
_ = passSubmit
|
||||
pathnames := make([]string,0)
|
||||
pathnames := make([]string, 0)
|
||||
|
||||
updateBtns := func() {
|
||||
passBtns = passBtns[:0]
|
||||
pathnames = pathnames[:0]
|
||||
mux.Lock()
|
||||
for _,x := range l {
|
||||
for _, x := range l {
|
||||
_, n := path.Split(x.Pathname)
|
||||
s := strings.Repeat(" /",x.Level)
|
||||
s := strings.Repeat(" /", x.Level)
|
||||
z := ""
|
||||
if x.Dir { z = "/" }
|
||||
passBtns = append(passBtns,&Button{
|
||||
Face:face,
|
||||
Label:strings.Join([]string{s,n,z},""),
|
||||
if x.Dir {
|
||||
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},
|
||||
})
|
||||
pathnames = append(pathnames, x.Pathname)
|
||||
|
@ -190,21 +190,20 @@ func eventLoop() {
|
|||
}
|
||||
updateBtns()
|
||||
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-updated:
|
||||
log(Info,"UPDATE")
|
||||
for {
|
||||
select {
|
||||
case <-updated:
|
||||
log(Info, "UPDATE")
|
||||
updateBtns()
|
||||
w.Invalidate()
|
||||
case e := <-w.Events():
|
||||
w.Invalidate()
|
||||
case e := <-w.Events():
|
||||
switch e := e.(type) {
|
||||
case app.DestroyEvent:
|
||||
return
|
||||
case app.UpdateEvent:
|
||||
c := &e.Config
|
||||
ops.Reset()
|
||||
faces.Reset(c)
|
||||
faces.Reset(c)
|
||||
var dims layout.Dimensions
|
||||
cs := layout.RigidConstraints(e.Size)
|
||||
cs = margin.Begin(c, ops, cs)
|
||||
|
@ -219,15 +218,15 @@ func eventLoop() {
|
|||
lst.End(dims)
|
||||
if btn.Clicked() {
|
||||
// don't block UI thread on decryption attempt
|
||||
log(Info,"Clicked ", btn.Label)
|
||||
log(Info, "Clicked ", btn.Label)
|
||||
go func(name string) {
|
||||
//p,err := store.Decrypt(name, prompt)
|
||||
p,err := store.Decrypt(name)
|
||||
p, err := store.Decrypt(name)
|
||||
if err == nil {
|
||||
gpass.Clip(p)
|
||||
passgo.Clip(p)
|
||||
} else {
|
||||
log(Info,"Can't decrypt ", name)
|
||||
log(Info,err)
|
||||
log(Info, "Can't decrypt ", name)
|
||||
log(Info, err)
|
||||
}
|
||||
}(pathnames[lst.Index()])
|
||||
}
|
||||
|
@ -235,9 +234,8 @@ func eventLoop() {
|
|||
mux.Unlock()
|
||||
dims = lst.Layout()
|
||||
dims = margin.End(dims)
|
||||
w.Update(ops)
|
||||
w.Update(ops)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,11 +6,11 @@ import (
|
|||
"path"
|
||||
"strings"
|
||||
|
||||
"git.wow.st/gmp/gpass"
|
||||
"git.wow.st/gmp/passgo"
|
||||
)
|
||||
|
||||
func usage() {
|
||||
fmt.Println("gpass [-c|--clip] [name]")
|
||||
fmt.Println("passgo [-c|--clip] [name]")
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
|
@ -18,53 +18,55 @@ type options struct {
|
|||
clip bool
|
||||
}
|
||||
|
||||
func parse(args []string) ([]string,options) {
|
||||
ret := make([]string,0)
|
||||
func parse(args []string) ([]string, options) {
|
||||
ret := make([]string, 0)
|
||||
opts := options{}
|
||||
for _,a := range args {
|
||||
for _, a := range args {
|
||||
switch {
|
||||
case a == "-c",a == "--clip":
|
||||
case a == "-c", a == "--clip":
|
||||
opts.clip = true
|
||||
case a[0] == '-':
|
||||
usage()
|
||||
default:
|
||||
ret = append(ret,a)
|
||||
ret = append(ret, a)
|
||||
}
|
||||
}
|
||||
return ret,opts
|
||||
return ret, opts
|
||||
}
|
||||
|
||||
func main() {
|
||||
store,err := gpass.GetStore()
|
||||
store, err := passgo.GetStore()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
args := os.Args[1:]
|
||||
args,opts := parse(args)
|
||||
args, opts := parse(args)
|
||||
switch len(args) {
|
||||
case 0:
|
||||
l,err := store.List()
|
||||
l, err := store.List()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(-1)
|
||||
}
|
||||
for _, x := range l {
|
||||
_, n := path.Split(x.Pathname)
|
||||
s := strings.Repeat(" /",x.Level)
|
||||
s := strings.Repeat(" /", x.Level)
|
||||
z := ""
|
||||
if x.Dir { z = "/" }
|
||||
fmt.Println(strings.Join([]string{s,n,z},""))
|
||||
if x.Dir {
|
||||
z = "/"
|
||||
}
|
||||
fmt.Println(strings.Join([]string{s, n, z}, ""))
|
||||
}
|
||||
case 1:
|
||||
p,err := store.Decrypt(args[0])
|
||||
p, err := store.Decrypt(args[0])
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(-1)
|
||||
}
|
||||
if opts.clip {
|
||||
gpass.Clip(p)
|
||||
passgo.Clip(p)
|
||||
} else {
|
||||
fmt.Print(p)
|
||||
}
|
||||
|
@ -72,4 +74,3 @@ func main() {
|
|||
usage()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
//+build !android !linux
|
||||
|
||||
package gpass
|
||||
package passgo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
|
@ -73,7 +73,7 @@ func setAgentInfo() {
|
|||
}
|
||||
s := fmt.Sprintf("%s:%d:1", filename, pid)
|
||||
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
|
||||
ask = GPGPrompt
|
||||
|
@ -90,4 +90,3 @@ func Clip(x string) {
|
|||
cmd.Stdin = b
|
||||
cmd.Run()
|
||||
}
|
||||
|
||||
|
|
75
main.go
75
main.go
|
@ -1,4 +1,4 @@
|
|||
package gpass
|
||||
package passgo
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
|
@ -22,7 +22,7 @@ import (
|
|||
|
||||
var (
|
||||
basename *regexp.Regexp
|
||||
ask openpgp.PromptFunction
|
||||
ask openpgp.PromptFunction
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -30,19 +30,19 @@ func init() {
|
|||
}
|
||||
|
||||
type Store struct {
|
||||
Dir string
|
||||
Dir string
|
||||
keyring openpgp.KeyRing
|
||||
}
|
||||
|
||||
func GetStore() (*Store, error) {
|
||||
ret := &Store{}
|
||||
u, err := user.Current()
|
||||
if err != nil {
|
||||
return ret, fmt.Errorf("Can't get current user.")
|
||||
}
|
||||
ret.Dir = path.Join(u.HomeDir,".password-store")
|
||||
u, err := user.Current()
|
||||
if err != nil {
|
||||
return ret, fmt.Errorf("Can't get current user.")
|
||||
}
|
||||
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()
|
||||
if err != nil {
|
||||
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.")
|
||||
}
|
||||
ret.keyring = kr
|
||||
return ret, nil
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
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) 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 {
|
||||
Pathname string
|
||||
Level int
|
||||
Dir bool
|
||||
Level int
|
||||
Dir bool
|
||||
}
|
||||
|
||||
func (s *Store) List() ([]Pass,error) {
|
||||
return s.list(0,"")
|
||||
func (s *Store) List() ([]Pass, error) {
|
||||
return s.list(0, "")
|
||||
}
|
||||
|
||||
func (s *Store) list(level int, p string) ([]Pass,error) {
|
||||
ret := make([]Pass,0)
|
||||
dir := path.Join(s.Dir,p)
|
||||
func (s *Store) list(level int, p string) ([]Pass, error) {
|
||||
ret := make([]Pass, 0)
|
||||
dir := path.Join(s.Dir, p)
|
||||
fd, err := os.Open(dir)
|
||||
defer fd.Close()
|
||||
if err != nil {
|
||||
|
@ -87,25 +87,25 @@ func (s *Store) list(level int, p string) ([]Pass,error) {
|
|||
}
|
||||
sort.Sort(caseInsensitive(files))
|
||||
for _, x := range files {
|
||||
n := basename.ReplaceAllLiteralString(x.Name(),"")
|
||||
entry := Pass{Pathname: path.Join(p,n),Level: level}
|
||||
n := basename.ReplaceAllLiteralString(x.Name(), "")
|
||||
entry := Pass{Pathname: path.Join(p, n), Level: level}
|
||||
|
||||
if n[0] == '.' {
|
||||
continue
|
||||
}
|
||||
if x.IsDir() {
|
||||
entry.Dir = true
|
||||
ret = append(ret,entry)
|
||||
l,err := s.list(level+1,path.Join(p,x.Name()))
|
||||
ret = append(ret, entry)
|
||||
l, err := s.list(level+1, path.Join(p, x.Name()))
|
||||
if err != nil {
|
||||
return nil,err
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret,l...)
|
||||
ret = append(ret, l...)
|
||||
} else {
|
||||
ret = append(ret,entry)
|
||||
ret = append(ret, entry)
|
||||
}
|
||||
}
|
||||
return ret,nil
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func AskPass(prompts ...func() []byte) openpgp.PromptFunction {
|
||||
|
@ -124,7 +124,7 @@ func AskPass(prompts ...func() []byte) openpgp.PromptFunction {
|
|||
var err error
|
||||
var passphrase []byte
|
||||
dec := func(p *packet.PrivateKey) {
|
||||
for i := 0; i<3; i++ {
|
||||
for i := 0; i < 3; i++ {
|
||||
if err = p.Decrypt(passphrase); err == nil {
|
||||
break
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ func AskPass(prompts ...func() []byte) openpgp.PromptFunction {
|
|||
var ret openpgp.PromptFunction
|
||||
ret = func(keys []openpgp.Key, symmetric bool) ([]byte, error) {
|
||||
if !symmetric {
|
||||
for _,k := range keys {
|
||||
for _, k := range keys {
|
||||
if p := k.PrivateKey; p != nil && p.Encrypted {
|
||||
dec(p)
|
||||
}
|
||||
|
@ -175,18 +175,18 @@ func GPGPrompt(keys []openpgp.Key, symmetric bool) ([]byte, error) {
|
|||
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 {
|
||||
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) {
|
||||
return "",fmt.Errorf("Not in password store.")
|
||||
return "", fmt.Errorf("Not in password store.")
|
||||
}
|
||||
fd, err := os.Open(file)
|
||||
defer fd.Close()
|
||||
if err != nil {
|
||||
return "",err
|
||||
return "", err
|
||||
}
|
||||
var reader io.Reader
|
||||
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)
|
||||
defer fd.Close()
|
||||
if err != nil {
|
||||
return "",err
|
||||
return "", err
|
||||
}
|
||||
reader = fd
|
||||
}
|
||||
md, err := openpgp.ReadMessage(reader,s.keyring,ask,nil)
|
||||
md, err := openpgp.ReadMessage(reader, s.keyring, ask, nil)
|
||||
if err != nil {
|
||||
fmt.Println("Error reading message")
|
||||
return "",err
|
||||
return "", err
|
||||
}
|
||||
ra, err := ioutil.ReadAll(md.UnverifiedBody)
|
||||
if err != nil {
|
||||
return "",err
|
||||
return "", err
|
||||
}
|
||||
return string(ra), nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user