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/passgo-gui/passgo-gui
 | 
			
		||||
cmd/gpass/passgo
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	//"fmt"
 | 
			
		||||
	"image"
 | 
			
		||||
	"image/color"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"gioui.org/ui"
 | 
			
		||||
	"gioui.org/ui/app"
 | 
			
		||||
| 
						 | 
				
			
			@ -25,47 +23,19 @@ import (
 | 
			
		|||
	"gioui.org/ui/text"
 | 
			
		||||
 | 
			
		||||
	"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"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type conf struct {
 | 
			
		||||
	StoreDir string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	var fd *os.File
 | 
			
		||||
	confFile := path.Join(confDir, "config.yml")
 | 
			
		||||
	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)
 | 
			
		||||
	var err error
 | 
			
		||||
	store, err = passgo.GetStore()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		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{})
 | 
			
		||||
 | 
			
		||||
	go Updater()
 | 
			
		||||
	log(Info, "Staring event loop")
 | 
			
		||||
	go eventLoop()
 | 
			
		||||
| 
						 | 
				
			
			@ -74,23 +44,17 @@ func main() {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	Config   conf
 | 
			
		||||
	l        []passgo.Pass
 | 
			
		||||
	mux      sync.Mutex
 | 
			
		||||
	store    passgo.Store
 | 
			
		||||
	reload   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}
 | 
			
		||||
	l       []passgo.Pass
 | 
			
		||||
	mux     sync.Mutex
 | 
			
		||||
	store   *passgo.Store
 | 
			
		||||
	updated chan struct{}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Updater() {
 | 
			
		||||
	update := func() {
 | 
			
		||||
		ltmp, err := store.List()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log(Info, err)
 | 
			
		||||
			log(Fatal, err)
 | 
			
		||||
		}
 | 
			
		||||
		mux.Lock()
 | 
			
		||||
		l = ltmp
 | 
			
		||||
| 
						 | 
				
			
			@ -106,8 +70,6 @@ func Updater() {
 | 
			
		|||
	watcher.Add(store.Dir)
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case <-reload:
 | 
			
		||||
			update()
 | 
			
		||||
		case <-watcher.Events:
 | 
			
		||||
			update()
 | 
			
		||||
		case e := <-watcher.Errors:
 | 
			
		||||
| 
						 | 
				
			
			@ -116,71 +78,12 @@ 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 {
 | 
			
		||||
	Face       text.Face
 | 
			
		||||
	Label      string
 | 
			
		||||
	Click      gesture.Click
 | 
			
		||||
	Color      color.RGBA
 | 
			
		||||
	Background color.RGBA
 | 
			
		||||
	Alignment  text.Alignment
 | 
			
		||||
	clicked    bool
 | 
			
		||||
	Face    text.Face
 | 
			
		||||
	Label   string
 | 
			
		||||
	Click   gesture.Click
 | 
			
		||||
	Color   color.RGBA
 | 
			
		||||
	clicked bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func layoutRRect(col color.RGBA, c ui.Config, ops *ui.Ops, cs layout.Constraints) layout.Dimensions {
 | 
			
		||||
| 
						 | 
				
			
			@ -210,7 +113,7 @@ func rrect(ops *ui.Ops, width, height, se, sw, nw, ne float32) {
 | 
			
		|||
	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
 | 
			
		||||
	for ev, ok := b.Click.Next(q); ok; ev, ok = b.Click.Next(q) {
 | 
			
		||||
		if ev.Type == gesture.TypeClick {
 | 
			
		||||
| 
						 | 
				
			
			@ -225,18 +128,16 @@ func (b *Button) Layout(c ui.Config, q input.Queue, ops *ui.Ops, cs layout.Const
 | 
			
		|||
	{
 | 
			
		||||
		cs = st.Rigid()
 | 
			
		||||
		l := text.Label{
 | 
			
		||||
			Face:      b.Face,
 | 
			
		||||
			Text:      b.Label,
 | 
			
		||||
			Alignment: b.Alignment,
 | 
			
		||||
			Face: b.Face,
 | 
			
		||||
			Text: b.Label,
 | 
			
		||||
		}
 | 
			
		||||
		ins := layout.UniformInset(ui.Dp(4))
 | 
			
		||||
		paint.ColorOp{Color: b.Color}.Add(ops)
 | 
			
		||||
		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)
 | 
			
		||||
		b.Click.Add(ops)
 | 
			
		||||
	}
 | 
			
		||||
	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)
 | 
			
		||||
	return ins.End(dims)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -248,43 +149,24 @@ func (b *Button) Clicked() bool {
 | 
			
		|||
func eventLoop() {
 | 
			
		||||
	w := app.NewWindow(app.WithWidth(ui.Dp(250)))
 | 
			
		||||
	q := w.Queue()
 | 
			
		||||
	var c ui.Config
 | 
			
		||||
	_ = q
 | 
			
		||||
	ops := new(ui.Ops)
 | 
			
		||||
	var dims layout.Dimensions
 | 
			
		||||
	var cs layout.Constraints
 | 
			
		||||
	var margincs layout.Constraints
 | 
			
		||||
	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))
 | 
			
		||||
 | 
			
		||||
	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.SetText("passphrase")
 | 
			
		||||
	passSubmit := &Button{Face: face, Label: "submit", Color: black}
 | 
			
		||||
	passSubmit := &Button{Face: face, Label: "submit"}
 | 
			
		||||
	lst := &layout.List{Axis: layout.Vertical}
 | 
			
		||||
	passBtns := make([]*Button, 0)
 | 
			
		||||
	_ = passInput
 | 
			
		||||
	_ = passSubmit
 | 
			
		||||
	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() {
 | 
			
		||||
		passBtns = passBtns[:0]
 | 
			
		||||
| 
						 | 
				
			
			@ -298,9 +180,9 @@ func eventLoop() {
 | 
			
		|||
				z = "/"
 | 
			
		||||
			}
 | 
			
		||||
			passBtns = append(passBtns, &Button{
 | 
			
		||||
				Face:       face,
 | 
			
		||||
				Label:      strings.Join([]string{s, n, z}, ""),
 | 
			
		||||
				Background: gray,
 | 
			
		||||
				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)
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -308,190 +190,50 @@ func eventLoop() {
 | 
			
		|||
	}
 | 
			
		||||
	updateBtns()
 | 
			
		||||
 | 
			
		||||
	confBtn := &Button{
 | 
			
		||||
		Face:       face,
 | 
			
		||||
		Label:      "configure",
 | 
			
		||||
		Alignment:  text.Middle,
 | 
			
		||||
		Color:      black,
 | 
			
		||||
		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()
 | 
			
		||||
	}
 | 
			
		||||
	animOff := func() {
 | 
			
		||||
		anim.Stop()
 | 
			
		||||
		animating = false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var listPage, confPage, page func()
 | 
			
		||||
	_ = confPage
 | 
			
		||||
 | 
			
		||||
	listPage = func() {
 | 
			
		||||
		cs = flex.Flexible(1.0)
 | 
			
		||||
		mux.Lock()
 | 
			
		||||
		if lst.Dragging() {
 | 
			
		||||
			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() {
 | 
			
		||||
				btn := passBtns[lst.Index()]
 | 
			
		||||
				dims = btn.Layout(c, q, ops, lst.Constraints())
 | 
			
		||||
				lst.End(dims)
 | 
			
		||||
				if btn.Clicked() {
 | 
			
		||||
					log(Info, "Clicked ", btn.Label)
 | 
			
		||||
					// don't block UI thread on decryption attempt
 | 
			
		||||
					go func(name string) {
 | 
			
		||||
						//p,err := store.Decrypt(name, prompt)
 | 
			
		||||
						p, err := store.Decrypt(name)
 | 
			
		||||
						if err == nil {
 | 
			
		||||
							passgo.Clip(p)
 | 
			
		||||
							copiedWhen = time.Now()
 | 
			
		||||
							animOn()
 | 
			
		||||
						} else {
 | 
			
		||||
							log(Info, "Can't decrypt ", name)
 | 
			
		||||
							log(Info, err)
 | 
			
		||||
						}
 | 
			
		||||
					}(pathnames[lst.Index()])
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			c2 = flex.End(lst.Layout())
 | 
			
		||||
		}
 | 
			
		||||
		mux.Unlock()
 | 
			
		||||
		if dotsbtn.Clicked() {
 | 
			
		||||
			log(Info, "Configure")
 | 
			
		||||
			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
 | 
			
		||||
				c := &e.Config
 | 
			
		||||
				ops.Reset()
 | 
			
		||||
				faces.Reset(c)
 | 
			
		||||
				cs = layout.RigidConstraints(e.Size)
 | 
			
		||||
				var dims layout.Dimensions
 | 
			
		||||
				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)
 | 
			
		||||
				mux.Lock()
 | 
			
		||||
				if lst.Dragging() {
 | 
			
		||||
					key.HideInputOp{}.Add(ops)
 | 
			
		||||
				}
 | 
			
		||||
				for lst.Init(c, q, ops, cs, len(passBtns)); lst.More(); lst.Next() {
 | 
			
		||||
					btn := passBtns[lst.Index()]
 | 
			
		||||
					dims = btn.Layout(c, ops, q, lst.Constraints())
 | 
			
		||||
					lst.End(dims)
 | 
			
		||||
					if btn.Clicked() {
 | 
			
		||||
						// don't block UI thread on decryption attempt
 | 
			
		||||
						log(Info, "Clicked ", btn.Label)
 | 
			
		||||
						go func(name string) {
 | 
			
		||||
							//p,err := store.Decrypt(name, prompt)
 | 
			
		||||
							p, err := store.Decrypt(name)
 | 
			
		||||
							if err == nil {
 | 
			
		||||
								passgo.Clip(p)
 | 
			
		||||
							} else {
 | 
			
		||||
								log(Info, "Can't decrypt ", name)
 | 
			
		||||
								log(Info, err)
 | 
			
		||||
							}
 | 
			
		||||
						}(pathnames[lst.Index()])
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				mux.Unlock()
 | 
			
		||||
				dims = lst.Layout()
 | 
			
		||||
				dims = margin.End(dims)
 | 
			
		||||
				w.Update(ops)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,8 +35,7 @@ func parse(args []string) ([]string, options) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	var store passgo.Store
 | 
			
		||||
	err := passgo.GetStore(&store)
 | 
			
		||||
	store, err := passgo.GetStore()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println(err)
 | 
			
		||||
		os.Exit(-1)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										17
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								main.go
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -34,26 +34,25 @@ type Store struct {
 | 
			
		|||
	keyring openpgp.KeyRing
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetStore(store *Store) error {
 | 
			
		||||
func GetStore() (*Store, error) {
 | 
			
		||||
	ret := &Store{}
 | 
			
		||||
	u, err := user.Current()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("Can't get current user.")
 | 
			
		||||
	}
 | 
			
		||||
	if store.Dir == "" {
 | 
			
		||||
		store.Dir = path.Join(u.HomeDir, ".password-store")
 | 
			
		||||
		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"))
 | 
			
		||||
	defer fd.Close()
 | 
			
		||||
	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)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("Can't open gnupg keyring.")
 | 
			
		||||
		return ret, fmt.Errorf("Can't open gnupg keyring.")
 | 
			
		||||
	}
 | 
			
		||||
	store.keyring = kr
 | 
			
		||||
	return nil
 | 
			
		||||
	ret.keyring = kr
 | 
			
		||||
	return ret, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type caseInsensitive []os.FileInfo
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user