Compare commits
	
		
			No commits in common. "7b3d59a581684d33637366ddde1fe74ecd127694" and "28ccd6d107fbb2224694bf2837c839fe0b89087f" have entirely different histories.
		
	
	
		
			7b3d59a581
			...
			28ccd6d107
		
	
		
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1,2 +1,2 @@
 | 
				
			||||||
cmd/passgo/passgo
 | 
					cmd/gpass/passgo
 | 
				
			||||||
cmd/passgo-gui/passgo-gui
 | 
					cmd/gpass-gui/passgo-gui
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,61 +0,0 @@
 | 
				
			||||||
//+build !android !linux
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"os"
 | 
					 | 
				
			||||||
	"os/user"
 | 
					 | 
				
			||||||
	"path"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"golang.org/x/image/font/gofont/goregular"
 | 
					 | 
				
			||||||
	"golang.org/x/image/font/sfnt"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var (
 | 
					 | 
				
			||||||
	regular *sfnt.Font
 | 
					 | 
				
			||||||
	confDir string
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func setFont() error {
 | 
					 | 
				
			||||||
	f, err := os.Open("/System/Library/Fonts/AppleSDGothicNeo.ttc")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log(Info, "Cannot open system font.")
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	collection, err := sfnt.ParseCollectionReaderAt(f)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log(Info, "Cannot parse system font.")
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	regular, err = collection.Font(0)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log(Info, "Cannot access first font in collection.")
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func init() {
 | 
					 | 
				
			||||||
	err := setFont()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		regular, err = sfnt.Parse(goregular.TTF)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			log(Fatal, "Cannot parse default font: ", err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	usr, err := user.Current()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log(Fatal, "Cannot get current user: ", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	confDir = path.Join(usr.HomeDir, ".config/passgo")
 | 
					 | 
				
			||||||
	if _, err := os.Stat(confDir); os.IsNotExist(err) {
 | 
					 | 
				
			||||||
		err = os.MkdirAll(confDir, 0700)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			log(Info, "Cannot create configuration directory ", confDir)
 | 
					 | 
				
			||||||
			log(Fatal, err)
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			log(Info, "Configuration directory created")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -3,14 +3,12 @@
 | 
				
			||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						//"fmt"
 | 
				
			||||||
	"image"
 | 
						"image"
 | 
				
			||||||
	"image/color"
 | 
						"image/color"
 | 
				
			||||||
	"io/ioutil"
 | 
					 | 
				
			||||||
	"os"
 | 
					 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"gioui.org/ui"
 | 
						"gioui.org/ui"
 | 
				
			||||||
	"gioui.org/ui/app"
 | 
						"gioui.org/ui/app"
 | 
				
			||||||
| 
						 | 
					@ -25,47 +23,19 @@ import (
 | 
				
			||||||
	"gioui.org/ui/text"
 | 
						"gioui.org/ui/text"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/fsnotify/fsnotify"
 | 
						"github.com/fsnotify/fsnotify"
 | 
				
			||||||
	"gopkg.in/yaml.v2"
 | 
						"golang.org/x/image/font/gofont/goregular"
 | 
				
			||||||
 | 
						"golang.org/x/image/font/sfnt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"git.wow.st/gmp/passgo"
 | 
						"git.wow.st/gmp/passgo"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type conf struct {
 | 
					 | 
				
			||||||
	StoreDir string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
	var fd *os.File
 | 
						var err error
 | 
				
			||||||
	confFile := path.Join(confDir, "config.yml")
 | 
						store, err = passgo.GetStore()
 | 
				
			||||||
	if _, err := os.Stat(confFile); os.IsNotExist(err) {
 | 
					 | 
				
			||||||
		fd, err = os.Create(confFile)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			log(Fatal, "Cannot create configuration file: ", err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	confbytes, err := ioutil.ReadFile(confFile)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log(Fatal, "Cannot read configuration file: ", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if err = yaml.UnmarshalStrict(confbytes, &Config); err != nil {
 | 
					 | 
				
			||||||
		log(Fatal, "Cannot parse configuration file: ", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	store.Dir = Config.StoreDir
 | 
					 | 
				
			||||||
	log(Info, " StoreDir = ", store.Dir)
 | 
					 | 
				
			||||||
	err = passgo.GetStore(&store)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log(Fatal, err)
 | 
							log(Fatal, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if fd != nil { // we still have an empty conf file open:
 | 
					 | 
				
			||||||
		Config.StoreDir = store.Dir
 | 
					 | 
				
			||||||
		saveConf(fd)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	reload = make(chan struct{})
 | 
					 | 
				
			||||||
	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()
 | 
				
			||||||
| 
						 | 
					@ -74,23 +44,17 @@ func main() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
	Config   conf
 | 
					 | 
				
			||||||
	l       []passgo.Pass
 | 
						l       []passgo.Pass
 | 
				
			||||||
	mux     sync.Mutex
 | 
						mux     sync.Mutex
 | 
				
			||||||
	store    passgo.Store
 | 
						store   *passgo.Store
 | 
				
			||||||
	reload   chan struct{}
 | 
					 | 
				
			||||||
	updated chan struct{}
 | 
						updated chan struct{}
 | 
				
			||||||
	black    = color.RGBA{A: 0xff, R: 0, G: 0, B: 0}
 | 
					 | 
				
			||||||
	white    = color.RGBA{A: 0xff, R: 0xff, G: 0xff, B: 0xff}
 | 
					 | 
				
			||||||
	gray     = color.RGBA{A: 0xff, R: 0xf0, G: 0xf0, B: 0xf0}
 | 
					 | 
				
			||||||
	darkgray = color.RGBA{A: 0xff, R: 0xa0, G: 0xa0, B: 0xa0}
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Updater() {
 | 
					func Updater() {
 | 
				
			||||||
	update := func() {
 | 
						update := func() {
 | 
				
			||||||
		ltmp, err := store.List()
 | 
							ltmp, err := store.List()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log(Info, err)
 | 
								log(Fatal, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		mux.Lock()
 | 
							mux.Lock()
 | 
				
			||||||
		l = ltmp
 | 
							l = ltmp
 | 
				
			||||||
| 
						 | 
					@ -106,8 +70,6 @@ func Updater() {
 | 
				
			||||||
	watcher.Add(store.Dir)
 | 
						watcher.Add(store.Dir)
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
		select {
 | 
							select {
 | 
				
			||||||
		case <-reload:
 | 
					 | 
				
			||||||
			update()
 | 
					 | 
				
			||||||
		case <-watcher.Events:
 | 
							case <-watcher.Events:
 | 
				
			||||||
			update()
 | 
								update()
 | 
				
			||||||
		case e := <-watcher.Errors:
 | 
							case e := <-watcher.Errors:
 | 
				
			||||||
| 
						 | 
					@ -116,70 +78,11 @@ func Updater() {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func saveConf(fds ...*os.File) {
 | 
					 | 
				
			||||||
	var fd *os.File
 | 
					 | 
				
			||||||
	var err error
 | 
					 | 
				
			||||||
	if len(fds) > 0 && fds[0] != nil {
 | 
					 | 
				
			||||||
		fd = fds[0]
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		fd, err = os.Create(path.Join(confDir, "config.yml"))
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			log(Fatal, "Cannot open config file: ", err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	confbytes, err := yaml.Marshal(Config)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log(Fatal, "Cannot save configuration: ", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	_, err = fd.Write(confbytes)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log(Fatal, "Cannot write to configuration: ", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Overlay struct {
 | 
					 | 
				
			||||||
	Face       text.Face
 | 
					 | 
				
			||||||
	Text       string
 | 
					 | 
				
			||||||
	Click      gesture.Click
 | 
					 | 
				
			||||||
	Color      color.RGBA
 | 
					 | 
				
			||||||
	Background color.RGBA
 | 
					 | 
				
			||||||
	Alignment  text.Alignment
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (b *Overlay) Layout(c ui.Config, ops *ui.Ops, cs layout.Constraints) layout.Dimensions {
 | 
					 | 
				
			||||||
	ins := layout.UniformInset(ui.Dp(1))
 | 
					 | 
				
			||||||
	cs = ins.Begin(c, ops, cs)
 | 
					 | 
				
			||||||
	var dims layout.Dimensions
 | 
					 | 
				
			||||||
	st := layout.Stack{}
 | 
					 | 
				
			||||||
	st.Init(ops, cs)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		cs = st.Rigid()
 | 
					 | 
				
			||||||
		l := text.Label{
 | 
					 | 
				
			||||||
			Face:      b.Face,
 | 
					 | 
				
			||||||
			Text:      b.Text,
 | 
					 | 
				
			||||||
			Alignment: b.Alignment,
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		ins := layout.UniformInset(ui.Dp(4))
 | 
					 | 
				
			||||||
		l.Material.Record(ops)
 | 
					 | 
				
			||||||
		paint.ColorOp{Color: b.Color}.Add(ops)
 | 
					 | 
				
			||||||
		l.Material.Stop()
 | 
					 | 
				
			||||||
		dims = ins.End(l.Layout(ops, ins.Begin(c, ops, cs)))
 | 
					 | 
				
			||||||
		pointer.RectAreaOp{image.Rect(0, 0, dims.Size.X, dims.Size.Y)}.Add(ops)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	c2 := st.End(dims)
 | 
					 | 
				
			||||||
	c1 := st.End(layoutRRect(b.Background, c, ops, st.Expand()))
 | 
					 | 
				
			||||||
	dims = st.Layout(c1, c2)
 | 
					 | 
				
			||||||
	return ins.End(dims)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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
 | 
				
			||||||
	Background color.RGBA
 | 
					 | 
				
			||||||
	Alignment  text.Alignment
 | 
					 | 
				
			||||||
	clicked bool
 | 
						clicked bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -210,7 +113,7 @@ func rrect(ops *ui.Ops, width, height, se, sw, nw, ne float32) {
 | 
				
			||||||
	b.End()
 | 
						b.End()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (b *Button) Layout(c ui.Config, q input.Queue, ops *ui.Ops, 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) {
 | 
				
			||||||
		if ev.Type == gesture.TypeClick {
 | 
							if ev.Type == gesture.TypeClick {
 | 
				
			||||||
| 
						 | 
					@ -227,16 +130,14 @@ func (b *Button) Layout(c ui.Config, q input.Queue, ops *ui.Ops, cs layout.Const
 | 
				
			||||||
		l := text.Label{
 | 
							l := text.Label{
 | 
				
			||||||
			Face: b.Face,
 | 
								Face: b.Face,
 | 
				
			||||||
			Text: b.Label,
 | 
								Text: b.Label,
 | 
				
			||||||
			Alignment: b.Alignment,
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ins := layout.UniformInset(ui.Dp(4))
 | 
							ins := layout.UniformInset(ui.Dp(4))
 | 
				
			||||||
		paint.ColorOp{Color: b.Color}.Add(ops)
 | 
					 | 
				
			||||||
		dims = ins.End(l.Layout(ops, ins.Begin(c, ops, cs)))
 | 
							dims = ins.End(l.Layout(ops, ins.Begin(c, ops, cs)))
 | 
				
			||||||
		pointer.RectAreaOp{image.Rect(0, 0, dims.Size.X, dims.Size.Y)}.Add(ops)
 | 
							pointer.RectAreaOp{image.Rect(0, 0, dims.Size.X, dims.Size.Y)}.Add(ops)
 | 
				
			||||||
		b.Click.Add(ops)
 | 
							b.Click.Add(ops)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	c2 := st.End(dims)
 | 
						c2 := st.End(dims)
 | 
				
			||||||
	c1 := st.End(layoutRRect(b.Background, c, ops, st.Expand()))
 | 
						c1 := st.End(layoutRRect(b.Color, c, ops, st.Expand()))
 | 
				
			||||||
	dims = st.Layout(c1, c2)
 | 
						dims = st.Layout(c1, c2)
 | 
				
			||||||
	return ins.End(dims)
 | 
						return ins.End(dims)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -248,43 +149,24 @@ func (b *Button) Clicked() bool {
 | 
				
			||||||
func eventLoop() {
 | 
					func eventLoop() {
 | 
				
			||||||
	w := app.NewWindow(app.WithWidth(ui.Dp(250)))
 | 
						w := app.NewWindow(app.WithWidth(ui.Dp(250)))
 | 
				
			||||||
	q := w.Queue()
 | 
						q := w.Queue()
 | 
				
			||||||
	var c ui.Config
 | 
						_ = q
 | 
				
			||||||
	ops := new(ui.Ops)
 | 
						ops := new(ui.Ops)
 | 
				
			||||||
	var dims layout.Dimensions
 | 
					 | 
				
			||||||
	var cs layout.Constraints
 | 
					 | 
				
			||||||
	var margincs layout.Constraints
 | 
					 | 
				
			||||||
	var faces measure.Faces
 | 
						var faces measure.Faces
 | 
				
			||||||
	var c1 layout.FlexChild // flex child for title bar
 | 
						regular, err := sfnt.Parse(goregular.TTF)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log(Fatal, "Cannot parse font.")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	face := faces.For(regular, ui.Sp(16))
 | 
						face := faces.For(regular, ui.Sp(16))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	margin := layout.UniformInset(ui.Dp(10))
 | 
						margin := layout.UniformInset(ui.Dp(10))
 | 
				
			||||||
 | 
					 | 
				
			||||||
	title := &text.Label{Face: face, Text: "passgo"}
 | 
					 | 
				
			||||||
	dotsbtn := &Button{
 | 
					 | 
				
			||||||
		Face:       face,
 | 
					 | 
				
			||||||
		Label:      "\xe2\x8b\xae",
 | 
					 | 
				
			||||||
		Alignment:  text.End,
 | 
					 | 
				
			||||||
		Color:      black,
 | 
					 | 
				
			||||||
		Background: gray,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	titleflex := &layout.Flex{Axis: layout.Horizontal}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	flex := &layout.Flex{Axis: layout.Vertical}
 | 
					 | 
				
			||||||
	passInput := &text.Editor{Face: face, SingleLine: true}
 | 
						passInput := &text.Editor{Face: face, SingleLine: true}
 | 
				
			||||||
	passInput.SetText("passphrase")
 | 
						passInput.SetText("passphrase")
 | 
				
			||||||
	passSubmit := &Button{Face: face, Label: "submit", Color: black}
 | 
						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)
 | 
				
			||||||
	copied := &Overlay{Face: face, Text: "copied to clipboard",
 | 
					 | 
				
			||||||
		Color:      black,
 | 
					 | 
				
			||||||
		Background: darkgray,
 | 
					 | 
				
			||||||
		Alignment:  text.Middle,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	var copiedWhen time.Time
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	updateBtns := func() {
 | 
						updateBtns := func() {
 | 
				
			||||||
		passBtns = passBtns[:0]
 | 
							passBtns = passBtns[:0]
 | 
				
			||||||
| 
						 | 
					@ -300,7 +182,7 @@ func eventLoop() {
 | 
				
			||||||
			passBtns = append(passBtns, &Button{
 | 
								passBtns = append(passBtns, &Button{
 | 
				
			||||||
				Face:  face,
 | 
									Face:  face,
 | 
				
			||||||
				Label: strings.Join([]string{s, n, z}, ""),
 | 
									Label: strings.Join([]string{s, n, z}, ""),
 | 
				
			||||||
				Background: gray,
 | 
									Color: color.RGBA{A: 0xff, R: 0xf0, G: 0xf0, B: 0xf0},
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
			pathnames = append(pathnames, x.Pathname)
 | 
								pathnames = append(pathnames, x.Pathname)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -308,76 +190,40 @@ func eventLoop() {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	updateBtns()
 | 
						updateBtns()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	confBtn := &Button{
 | 
						for {
 | 
				
			||||||
		Face:       face,
 | 
							select {
 | 
				
			||||||
		Label:      "configure",
 | 
							case <-updated:
 | 
				
			||||||
		Alignment:  text.Middle,
 | 
								log(Info, "UPDATE")
 | 
				
			||||||
		Color:      black,
 | 
								updateBtns()
 | 
				
			||||||
		Background: gray,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	storeDirLabel := &text.Label{Face: face, Text: "Store directory"}
 | 
					 | 
				
			||||||
	storeDirEd := &text.Editor{Face: face, SingleLine: true}
 | 
					 | 
				
			||||||
	storeDirEd.SetText(store.Dir)
 | 
					 | 
				
			||||||
	saveBtn := &Button{
 | 
					 | 
				
			||||||
		Face:       face,
 | 
					 | 
				
			||||||
		Label:      "save",
 | 
					 | 
				
			||||||
		Alignment:  text.End,
 | 
					 | 
				
			||||||
		Color:      black,
 | 
					 | 
				
			||||||
		Background: gray,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	backBtn := &Button{
 | 
					 | 
				
			||||||
		Face:       face,
 | 
					 | 
				
			||||||
		Label:      "back",
 | 
					 | 
				
			||||||
		Alignment:  text.End,
 | 
					 | 
				
			||||||
		Color:      black,
 | 
					 | 
				
			||||||
		Background: gray,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	anim := &time.Ticker{}
 | 
					 | 
				
			||||||
	animating := false
 | 
					 | 
				
			||||||
	animOn := func() {
 | 
					 | 
				
			||||||
		anim = time.NewTicker(time.Second / 120)
 | 
					 | 
				
			||||||
		animating = true
 | 
					 | 
				
			||||||
			w.Invalidate()
 | 
								w.Invalidate()
 | 
				
			||||||
	}
 | 
							case e := <-w.Events():
 | 
				
			||||||
	animOff := func() {
 | 
								switch e := e.(type) {
 | 
				
			||||||
		anim.Stop()
 | 
								case app.DestroyEvent:
 | 
				
			||||||
		animating = false
 | 
									return
 | 
				
			||||||
	}
 | 
								case app.UpdateEvent:
 | 
				
			||||||
 | 
									c := &e.Config
 | 
				
			||||||
 | 
									ops.Reset()
 | 
				
			||||||
 | 
									faces.Reset(c)
 | 
				
			||||||
 | 
									var dims layout.Dimensions
 | 
				
			||||||
 | 
									cs := layout.RigidConstraints(e.Size)
 | 
				
			||||||
 | 
									cs = margin.Begin(c, ops, cs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var listPage, confPage, page func()
 | 
					 | 
				
			||||||
	_ = confPage
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	listPage = func() {
 | 
					 | 
				
			||||||
		cs = flex.Flexible(1.0)
 | 
					 | 
				
			||||||
				mux.Lock()
 | 
									mux.Lock()
 | 
				
			||||||
				if lst.Dragging() {
 | 
									if lst.Dragging() {
 | 
				
			||||||
					key.HideInputOp{}.Add(ops)
 | 
										key.HideInputOp{}.Add(ops)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
		var c2 layout.FlexChild
 | 
					 | 
				
			||||||
		if len(passBtns) == 0 {
 | 
					 | 
				
			||||||
			c2 = flex.End(confBtn.Layout(c, q, ops, cs))
 | 
					 | 
				
			||||||
			if confBtn.Clicked() {
 | 
					 | 
				
			||||||
				log(Info, "Configure")
 | 
					 | 
				
			||||||
				w.Invalidate()
 | 
					 | 
				
			||||||
				page = confPage
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
				for lst.Init(c, q, ops, cs, len(passBtns)); lst.More(); lst.Next() {
 | 
									for lst.Init(c, q, ops, cs, len(passBtns)); lst.More(); lst.Next() {
 | 
				
			||||||
					btn := passBtns[lst.Index()]
 | 
										btn := passBtns[lst.Index()]
 | 
				
			||||||
				dims = btn.Layout(c, q, ops, lst.Constraints())
 | 
										dims = btn.Layout(c, ops, q, lst.Constraints())
 | 
				
			||||||
					lst.End(dims)
 | 
										lst.End(dims)
 | 
				
			||||||
					if btn.Clicked() {
 | 
										if btn.Clicked() {
 | 
				
			||||||
					log(Info, "Clicked ", btn.Label)
 | 
					 | 
				
			||||||
						// don't block UI thread on decryption attempt
 | 
											// don't block UI thread on decryption attempt
 | 
				
			||||||
 | 
											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 {
 | 
				
			||||||
								passgo.Clip(p)
 | 
													passgo.Clip(p)
 | 
				
			||||||
							copiedWhen = time.Now()
 | 
					 | 
				
			||||||
							animOn()
 | 
					 | 
				
			||||||
							} else {
 | 
												} else {
 | 
				
			||||||
								log(Info, "Can't decrypt ", name)
 | 
													log(Info, "Can't decrypt ", name)
 | 
				
			||||||
								log(Info, err)
 | 
													log(Info, err)
 | 
				
			||||||
| 
						 | 
					@ -385,113 +231,9 @@ func eventLoop() {
 | 
				
			||||||
						}(pathnames[lst.Index()])
 | 
											}(pathnames[lst.Index()])
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			c2 = flex.End(lst.Layout())
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
				mux.Unlock()
 | 
									mux.Unlock()
 | 
				
			||||||
		if dotsbtn.Clicked() {
 | 
									dims = lst.Layout()
 | 
				
			||||||
			log(Info, "Configure")
 | 
									dims = margin.End(dims)
 | 
				
			||||||
			w.Invalidate()
 | 
					 | 
				
			||||||
			page = confPage
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		flex.Layout(c1, c2)
 | 
					 | 
				
			||||||
		x := time.Since(copiedWhen).Seconds()
 | 
					 | 
				
			||||||
		start, end := 1.5, 1.75
 | 
					 | 
				
			||||||
		switch {
 | 
					 | 
				
			||||||
		case x > start && x < end:
 | 
					 | 
				
			||||||
			fade := (end - x) / (end - start)
 | 
					 | 
				
			||||||
			copied.Color.R = uint8(float64(black.R) * fade)
 | 
					 | 
				
			||||||
			copied.Color.G = uint8(float64(black.G) * fade)
 | 
					 | 
				
			||||||
			copied.Color.B = uint8(float64(black.B) * fade)
 | 
					 | 
				
			||||||
			copied.Color.A = uint8(float64(black.A) * fade)
 | 
					 | 
				
			||||||
			copied.Background.R = uint8(float64(darkgray.R) * fade)
 | 
					 | 
				
			||||||
			copied.Background.G = uint8(float64(darkgray.G) * fade)
 | 
					 | 
				
			||||||
			copied.Background.B = uint8(float64(darkgray.B) * fade)
 | 
					 | 
				
			||||||
			copied.Background.A = uint8(float64(darkgray.A) * fade)
 | 
					 | 
				
			||||||
			fallthrough
 | 
					 | 
				
			||||||
		case x <= start:
 | 
					 | 
				
			||||||
			cs = margincs
 | 
					 | 
				
			||||||
			al := layout.Align{Alignment: layout.SE}
 | 
					 | 
				
			||||||
			cs = al.Begin(ops, cs)
 | 
					 | 
				
			||||||
			cs.Width.Min = cs.Width.Max
 | 
					 | 
				
			||||||
			dims = al.End(copied.Layout(c, ops, cs))
 | 
					 | 
				
			||||||
		case animating:
 | 
					 | 
				
			||||||
			copied.Color = black
 | 
					 | 
				
			||||||
			copied.Background = darkgray
 | 
					 | 
				
			||||||
			animOff()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	confPage = func() {
 | 
					 | 
				
			||||||
		cs = flex.Rigid()
 | 
					 | 
				
			||||||
		c2 := flex.End(storeDirLabel.Layout(ops, cs))
 | 
					 | 
				
			||||||
		cs = flex.Rigid()
 | 
					 | 
				
			||||||
		c3 := flex.End(storeDirEd.Layout(c, q, ops, cs))
 | 
					 | 
				
			||||||
		cs = flex.Rigid()
 | 
					 | 
				
			||||||
		al := &layout.Align{Alignment: layout.E}
 | 
					 | 
				
			||||||
		cs = al.Begin(ops, cs)
 | 
					 | 
				
			||||||
		btnflx := &layout.Flex{Axis: layout.Horizontal}
 | 
					 | 
				
			||||||
		btnflx.Init(ops, cs)
 | 
					 | 
				
			||||||
		cs = btnflx.Rigid()
 | 
					 | 
				
			||||||
		bc1 := btnflx.End(backBtn.Layout(c, q, ops, cs))
 | 
					 | 
				
			||||||
		cs = btnflx.Rigid()
 | 
					 | 
				
			||||||
		bc2 := btnflx.End(saveBtn.Layout(c, q, ops, cs))
 | 
					 | 
				
			||||||
		dims = btnflx.Layout(bc1, bc2)
 | 
					 | 
				
			||||||
		c4 := flex.End(al.End(dims))
 | 
					 | 
				
			||||||
		flex.Layout(c1, c2, c3, c4)
 | 
					 | 
				
			||||||
		if backBtn.Clicked() {
 | 
					 | 
				
			||||||
			log(Info, "Back")
 | 
					 | 
				
			||||||
			storeDirEd.SetText(store.Dir)
 | 
					 | 
				
			||||||
			w.Invalidate()
 | 
					 | 
				
			||||||
			page = listPage
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if saveBtn.Clicked() {
 | 
					 | 
				
			||||||
			log(Info, "Save")
 | 
					 | 
				
			||||||
			go func() { // do not block UI thread
 | 
					 | 
				
			||||||
				store.Dir = storeDirEd.Text()
 | 
					 | 
				
			||||||
				passgo.GetStore(&store)
 | 
					 | 
				
			||||||
				Config.StoreDir = store.Dir
 | 
					 | 
				
			||||||
				saveConf()
 | 
					 | 
				
			||||||
				reload <- struct{}{}
 | 
					 | 
				
			||||||
			}()
 | 
					 | 
				
			||||||
			w.Invalidate()
 | 
					 | 
				
			||||||
			page = listPage
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	page = listPage
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for {
 | 
					 | 
				
			||||||
		select {
 | 
					 | 
				
			||||||
		case <-updated:
 | 
					 | 
				
			||||||
			log(Info, "UPDATE")
 | 
					 | 
				
			||||||
			updateBtns()
 | 
					 | 
				
			||||||
			w.Invalidate()
 | 
					 | 
				
			||||||
		case <-anim.C:
 | 
					 | 
				
			||||||
			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)
 | 
					 | 
				
			||||||
				cs = layout.RigidConstraints(e.Size)
 | 
					 | 
				
			||||||
				cs = margin.Begin(c, ops, cs)
 | 
					 | 
				
			||||||
				margincs = cs
 | 
					 | 
				
			||||||
				flex.Init(ops, cs)
 | 
					 | 
				
			||||||
				cs = flex.Rigid()
 | 
					 | 
				
			||||||
				titleflex.Init(ops, cs)
 | 
					 | 
				
			||||||
				cs = titleflex.Rigid()
 | 
					 | 
				
			||||||
				ct2 := titleflex.End(dotsbtn.Layout(c, q, ops, cs))
 | 
					 | 
				
			||||||
				cs = titleflex.Flexible(1.0)
 | 
					 | 
				
			||||||
				cs.Width.Min = cs.Width.Max
 | 
					 | 
				
			||||||
				ct1 := titleflex.End(title.Layout(ops, cs))
 | 
					 | 
				
			||||||
				c1 = flex.End(titleflex.Layout(ct1, ct2))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				page()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				margin.End(dims)
 | 
					 | 
				
			||||||
				w.Update(ops)
 | 
									w.Update(ops)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,8 +35,7 @@ func parse(args []string) ([]string, options) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
	var store passgo.Store
 | 
						store, err := passgo.GetStore()
 | 
				
			||||||
	err := passgo.GetStore(&store)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		fmt.Println(err)
 | 
							fmt.Println(err)
 | 
				
			||||||
		os.Exit(-1)
 | 
							os.Exit(-1)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										17
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								main.go
									
									
									
									
									
								
							| 
						 | 
					@ -34,26 +34,25 @@ type Store struct {
 | 
				
			||||||
	keyring openpgp.KeyRing
 | 
						keyring openpgp.KeyRing
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GetStore(store *Store) error {
 | 
					func GetStore() (*Store, error) {
 | 
				
			||||||
 | 
						ret := &Store{}
 | 
				
			||||||
	u, err := user.Current()
 | 
						u, err := user.Current()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return fmt.Errorf("Can't get current user.")
 | 
							return ret, fmt.Errorf("Can't get current user.")
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if store.Dir == "" {
 | 
					 | 
				
			||||||
		store.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 fmt.Errorf("Can't open keyring file")
 | 
							return ret, fmt.Errorf("Can't open keyring file")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	kr, err := openpgp.ReadKeyRing(fd)
 | 
						kr, err := openpgp.ReadKeyRing(fd)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return fmt.Errorf("Can't open gnupg keyring.")
 | 
							return ret, fmt.Errorf("Can't open gnupg keyring.")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	store.keyring = kr
 | 
						ret.keyring = kr
 | 
				
			||||||
	return nil
 | 
						return ret, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type caseInsensitive []os.FileInfo
 | 
					type caseInsensitive []os.FileInfo
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user