package service import ( "bufio" "bytes" "context" "fmt" "os" "strings" "text/tabwriter" "github.com/urfave/cli" ) func userCommands(client *Client) []cli.Command { return []cli.Command{ cli.Command{ Name: "user", Usage: "Link and search users", Subcommands: []cli.Command{ cli.Command{ Name: "find", Usage: "Find by kid", Flags: []cli.Flag{ cli.StringFlag{Name: "kid, k", Usage: "key"}, cli.BoolFlag{Name: "local", Usage: "search local index only"}, }, Action: func(c *cli.Context) error { kid, err := argString(c, "kid", false) if err != nil { return err } resp, err := client.RPCClient().User(context.TODO(), &UserRequest{ KID: kid, Local: c.Bool("local"), }) if err != nil { return err } if resp.User != nil { fmt.Println(fmtUser(resp.User)) } return nil }, }, cli.Command{ Name: "search", Usage: "Search for users", Flags: []cli.Flag{ cli.StringFlag{Name: "query, q", Usage: "query"}, cli.IntFlag{Name: "limit, l", Usage: "limit number of results"}, cli.BoolFlag{Name: "local", Usage: "search local index only"}, }, Action: func(c *cli.Context) error { query, err := argString(c, "query", true) if err != nil { return err } searchResp, err := client.RPCClient().UserSearch(context.TODO(), &UserSearchRequest{ Query: query, Limit: int32(c.Int("limit")), Local: c.Bool("local"), }) if err != nil { return err } out := &bytes.Buffer{} w := new(tabwriter.Writer) w.Init(out, 0, 8, 1, ' ', 0) for _, user := range searchResp.Users { fmt.Fprintf(w, "%s\t%s\n", fmtUser(user), user.KID) } if err := w.Flush(); err != nil { return err } fmt.Print(out.String()) return nil }, }, cli.Command{ Name: "setup", Usage: "Link a key to an account (Twitter, Github, Reddit)", Flags: []cli.Flag{ cli.StringFlag{Name: "kid, k", Usage: "key"}, }, Action: func(c *cli.Context) error { kid, err := argString(c, "kid", false) if err != nil { return err } reader := bufio.NewReader(os.Stdin) fmt.Println("What's the service? ") fmt.Println("(g) Github") fmt.Println("(t) Twitter") fmt.Println("(r) Reddit") input, err := reader.ReadString('\n') if err != nil { return err } service := "" question := "" switch strings.TrimSpace(strings.ToLower(input)) { case "g", "github": service = "github" question = "What's your Github username?" case "t", "twitter": service = "twitter" question = "What's your Twitter handle?" case "r", "reddit": service = "reddit" question = "What's your Reddit username?" } fmt.Println("") fmt.Print(question + " ") uin, err := reader.ReadString('\n') if err != nil { return err } name := strings.TrimSpace(strings.ToLower(uin)) signResp, err := client.RPCClient().UserSign(context.TODO(), &UserSignRequest{ KID: kid, Service: service, Name: name, }) if err != nil { return err } instructions := "" link := "" urlq := "" switch service { case "github": instructions = "Create a new gist on your Github account, and paste the signed message there." link = "https://gist.github.com/new" urlq = "What's the location (URL) on github.com where the signed message was saved?" case "twitter": instructions = "Save the following signed message as a tweet on your Twitter account." link = "https://twitter.com/intent/tweet" urlq = "What's the location (URL) on twitter.com where the signed message tweet was saved?" case "reddit": instructions = "Save the following signed message as a post on /r/keyspubmsgs." link = "https://old.reddit.com/r/keyspubmsgs/submit" urlq = "What's the location (URL) on reddit.com/r/keyspubmsgs where the signed message was posted?" } fmt.Println("") fmt.Println(instructions) fmt.Println(link) fmt.Println("") fmt.Println(signResp.Message) fmt.Println("") fmt.Print("Have you posted the signed message (Y/n)? ") proceed, err := reader.ReadString('\n') if err != nil { return err } switch strings.TrimSpace(strings.ToLower(proceed)) { case "y", "yes", "": default: return nil } fmt.Print(urlq + " ") surl, err := reader.ReadString('\n') if err != nil { return err } url := strings.TrimSpace(strings.ToLower(surl)) _, err = client.RPCClient().UserAdd(context.TODO(), &UserAddRequest{ KID: kid, Service: service, Name: name, URL: url, }) if err != nil { return err } // fmt.Printf("%s %s %s\n", setResp.User.KID, setResp.User.DisplayName, setResp.User.URL) fmt.Println("User successfully setup.") return nil }, }, cli.Command{ Name: "sign", Usage: "Create a signed user statement", ArgsUsage: "", Flags: []cli.Flag{ cli.StringFlag{Name: "kid, k", Usage: "key"}, cli.StringFlag{Name: "service"}, cli.StringFlag{Name: "name"}, }, Action: func(c *cli.Context) error { resp, err := client.RPCClient().UserSign(context.TODO(), &UserSignRequest{ KID: c.String("kid"), Service: c.String("service"), Name: c.String("name"), }) if err != nil { return err } fmt.Println(resp.Message) return nil }, }, cli.Command{ Name: "add", Usage: "Add a verified user statement to a sigchain", ArgsUsage: "", Flags: []cli.Flag{ cli.StringFlag{Name: "kid, k", Usage: "key"}, cli.StringFlag{Name: "service"}, cli.StringFlag{Name: "name"}, cli.StringFlag{Name: "url", Usage: "URL to signed statement created by `keys user sign`"}, cli.BoolFlag{Name: "local", Usage: "Don't save to the key server"}, }, Action: func(c *cli.Context) error { resp, err := client.RPCClient().UserAdd(context.TODO(), &UserAddRequest{ KID: c.String("kid"), Service: c.String("service"), Name: c.String("name"), URL: c.String("url"), Local: c.Bool("local"), }) if err != nil { return err } st, err := statementFromRPC(resp.Statement) if err != nil { return err } b, err := st.Bytes() if err != nil { return err } fmt.Printf("%s\n", string(b)) return nil }, }, }, }, } }