diff --git a/cache.go b/cache.go new file mode 100644 index 0000000..6842ed8 --- /dev/null +++ b/cache.go @@ -0,0 +1,50 @@ +package sshvault + +import ( + "fmt" + "io/ioutil" + "log" + "os" + "os/user" + "path/filepath" +) + +type cache struct { + dir string +} + +func Cache() *cache { + usr, _ := user.Current() + sv := filepath.Join(usr.HomeDir, ".ssh-vault", "keys") + if _, err := os.Stat(sv); os.IsNotExist(err) { + os.MkdirAll(sv, os.ModePerm) + } + return &cache{sv} +} + +func (c *cache) Get(u string) (string, error) { + uKey := fmt.Sprintf("%s/%s.key", c.dir, u) + if c.isFile(uKey) { + // read from file and return + } + key, err := GetKey(u) + if err != nil { + return "", err + } + err = ioutil.WriteFile(uKey, []byte(key), 0644) + if err != nil { + log.Println(err) + } + return key, nil +} + +func (c *cache) isFile(path string) bool { + f, err := os.Stat(path) + if err != nil { + return false + } + if m := f.Mode(); !m.IsDir() && m.IsRegular() && m&400 != 0 { + return true + } + return false +} diff --git a/cmd/ssh-vault/main.go b/cmd/ssh-vault/main.go index b900f2c..aed47fb 100644 --- a/cmd/ssh-vault/main.go +++ b/cmd/ssh-vault/main.go @@ -4,6 +4,8 @@ import ( "flag" "fmt" "os" + "os/user" + "path/filepath" sv "github.com/ssh-vault/ssh-vault" ) @@ -11,22 +13,58 @@ import ( var version string func main() { - parser := &sv.Parse{} + var ( + k = flag.String("k", "~/.ssh/id_rsa.pub", "public `ssh key`") + u = flag.String("u", "", "GitHub `username`") + options = []string{"create", "decrypt", "edit", "encrypt", "view"} + v = flag.Bool("v", false, fmt.Sprintf("Print version: %s", version)) + ) - // flag set - fs := flag.NewFlagSet(os.Args[0], flag.ExitOnError) - fs.Usage = parser.Usage(fs) - - err := sv.ParseArgs(parser, fs) - if err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) + flag.Usage = func() { + fmt.Fprintf(os.Stderr, "Usage: %s [-k key] [-u user] [create|decrypt|edit|encrypt|view] vault\n\n%s\n%s\n%s\n%s\n%s\n%s\n\n", + os.Args[0], + " Options:", + " create creates a new vault", + " decrypt decrypt a file", + " edit open an existing vault", + " encrypt encrypt a file", + " view open an existing vault") + flag.PrintDefaults() } - // if -v print version - if (fs.Lookup("v")).Value.(flag.Getter).Get().(bool) { + flag.Parse() + + if *v { fmt.Printf("%s\n", version) os.Exit(0) } + if flag.NArg() < 1 { + fmt.Printf("Missing option, use (\"%s -h\") for help.\n", os.Args[0]) + os.Exit(1) + } + + exit := true + for _, v := range options { + if flag.Arg(0) == v { + exit = false + break + } + } + if exit { + fmt.Printf("Invalid option, use (\"%s -h\") for help.\n", os.Args[0]) + os.Exit(1) + } + + if flag.NArg() < 2 { + fmt.Printf("Missing vault name, use (\"%s -h\") for help.\n", os.Args[0]) + os.Exit(1) + } + + usr, _ := user.Current() + if (*k)[:2] == "~/" { + *k = filepath.Join(usr.HomeDir, (*k)[2:]) + } + + sv.New(*k, *u, flag.Arg(0), flag.Arg(1)) } diff --git a/flags.go b/flags.go deleted file mode 100644 index 7b6b5f1..0000000 --- a/flags.go +++ /dev/null @@ -1,11 +0,0 @@ -package sshvault - -// Flags available command flags -type Flags struct { - Version bool - Create string - Decrypt string - Edit string - Encrypt string - View string -} diff --git a/getkey.go b/getkey.go new file mode 100644 index 0000000..4668c4b --- /dev/null +++ b/getkey.go @@ -0,0 +1,35 @@ +package sshvault + +import ( + "bufio" + "fmt" + "net/http" + "net/textproto" + "strings" +) + +const GITHUB = "https://github.com" + +func GetKey(u string) (string, error) { + client := &http.Client{} + // create a new request + req, _ := http.NewRequest("GET", fmt.Sprintf("%s/%s.keys", + GITHUB, + u), + nil) + req.Header.Set("User-Agent", "ssh-vault") + res, err := client.Do(req) + if err != nil { + return "", err + } + defer res.Body.Close() + reader := bufio.NewReader(res.Body) + tp := textproto.NewReader(reader) + for { + if line, err := tp.ReadLine(); err != nil { + return "", err + } else if strings.HasPrefix(line, "ssh-") { + return line, nil + } + } +} diff --git a/parser.go b/parser.go deleted file mode 100644 index 51fb15a..0000000 --- a/parser.go +++ /dev/null @@ -1,106 +0,0 @@ -package sshvault - -import ( - "flag" - "fmt" - "os" - "sort" -) - -// Parser interface -type Parser interface { - Parse(fs *flag.FlagSet) (*Flags, error) - isDir(path string) bool - isFile(path string) bool -} - -// Parse implements parser -type Parse struct { - Flags -} - -// Parse parse the command line flags -func (p *Parse) Parse(fs *flag.FlagSet) (*Flags, error) { - fs.BoolVar(&p.Flags.Version, "v", false, "Print version") - fs.StringVar(&p.Flags.Create, "c", "", "create vault") - - err := fs.Parse(os.Args[1:]) - if err != nil { - return nil, err - } - return &p.Flags, nil -} -func (p *Parse) Usage(fs *flag.FlagSet) func() { - return func() { - fmt.Fprintf(os.Stderr, "Usage: %s [create|decrypt|edit|encrypt|view] [-k key] [-u user] vault\n\n", os.Args[0]) - var flags []string - fs.VisitAll(func(f *flag.Flag) { - flags = append(flags, f.Name) - }) - sort.Strings(flags) - for _, v := range flags { - f := fs.Lookup(v) - s := fmt.Sprintf(" -%s", f.Name) - name, usage := flag.UnquoteUsage(f) - if len(name) > 0 { - s += " " + name - } - if len(s) <= 4 { - s += "\t" - } else { - s += "\n \t" - } - s += usage - fmt.Fprintf(os.Stderr, "%s\n", s) - } - } -} - -func (p *Parse) isDir(path string) bool { - f, err := os.Stat(path) - if err != nil { - return false - } - if m := f.Mode(); m.IsDir() && m&400 != 0 { - return true - } - return false -} - -func (p *Parse) isFile(path string) bool { - f, err := os.Stat(path) - if err != nil { - return false - } - if m := f.Mode(); !m.IsDir() && m.IsRegular() && m&400 != 0 { - return true - } - return false -} - -func (p *Parse) checkWrkdir(dir string) (err error) { - if !p.isDir(dir) { - err = fmt.Errorf("-d %q does not exist or has wrong permissions, use (\"%s -h\") for help.", dir, os.Args[0]) - } - return -} - -// ParseArgs parse command arguments -func ParseArgs(p Parser, fs *flag.FlagSet) (err error) { - flags, err := p.Parse(fs) - if err != nil { - return - } - - // if -v - if flags.Version { - return - } - - // if no args - if len(fs.Args()) < 1 { - err = fmt.Errorf("Missing user, use (\"%s -h\") for help.", os.Args[0]) - return - } - return -} diff --git a/vault.go b/vault.go new file mode 100644 index 0000000..6d05b97 --- /dev/null +++ b/vault.go @@ -0,0 +1,24 @@ +package sshvault + +import "fmt" + +// Vault structure +type Vault struct { + key string + user string + option string + vault string +} + +// New initialize vault parameters +func New(k, u, o, v string) error { + cache := Cache() + if u != "" { + path, err := cache.Get(u) + if err != nil { + return err + } + fmt.Printf("path = %+v\n", path) + } + return nil +}