// Package ssh groups the commands that derive ed25519 SSH keys. package ssh import ( "fmt" "git.eeqj.de/sneak/keyfunc/internal/cli/options" "git.eeqj.de/sneak/keyfunc/internal/derive" "git.eeqj.de/sneak/keyfunc/internal/sshkey" "github.com/spf13/cobra" ) // Command returns the ssh command and everything under it. func Command() *cobra.Command { group := &cobra.Command{ Use: "ssh", Short: "derive ed25519 SSH keys", } group.AddCommand(public(), private()) return group } // public returns the command that prints the authorized_keys line. func public() *cobra.Command { cmd := &cobra.Command{ Use: "pub", Short: "print the public key as an authorized_keys line", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { key, comment, err := derived(cmd) if err != nil { return err } line, err := key.Line(comment) if err != nil { return err } return write(cmd, line+"\n") }, } addComment(cmd) return cmd } // private returns the command that prints the private key. func private() *cobra.Command { cmd := &cobra.Command{ Use: "priv", Short: "print the unencrypted private key in OpenSSH format", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { key, comment, err := derived(cmd) if err != nil { return err } block, err := key.Block(comment) if err != nil { return err } return write(cmd, block) }, } addComment(cmd) return cmd } // write sends the text to wherever the command's output goes. func write(cmd *cobra.Command, text string) error { _, err := fmt.Fprint(cmd.OutOrStdout(), text) if err != nil { return fmt.Errorf("writing the key: %w", err) } return nil } // addComment gives a command its comment flag. func addComment(cmd *cobra.Command) { cmd.Flags().String( "comment", "", "comment on the key; keyfunc/ssh/ when not given", ) } // derived returns the key for this run and the comment to put on it. func derived(cmd *cobra.Command) (*sshkey.Key, string, error) { index, err := options.Index(cmd) if err != nil { return nil, "", err } words, err := options.Mnemonic(cmd) if err != nil { return nil, "", err } material, err := derive.Bytes(words, sshkey.Application, index) if err != nil { return nil, "", err } key, err := sshkey.New(material) if err != nil { return nil, "", err } comment, err := cmd.Flags().GetString("comment") if err != nil { return nil, "", fmt.Errorf("reading the comment: %w", err) } if comment == "" { comment = fmt.Sprintf("keyfunc/ssh/%d", index) } return key, comment, nil }