All checks were successful
check / check (push) Successful in 21s
install runs the system ssh and hands the host a short shell script to run, with the public key line on the connection's standard input rather than on a command line, where anyone else on the host could read it out of the process list. The script makes ~/.ssh and authorized_keys if they are missing, adds the line unless the same line is already there, and says which of the two it did. to serves the key from an agent inside the tool, on a unix socket in a temporary directory only its owner can enter, and points ssh at it with -o IdentityAgent. The socket and directory go when the command ends and the private key is never written to disk. Only this command hands back the status ssh ended with instead of ending with status 1. The tests put a stand-in ssh on the path: for install it runs the script the tool sends against a directory standing in for the host's home directory, so the file, the modes and the second run that changes nothing are all watched happening. Model: opus-5
128 lines
2.6 KiB
Go
128 lines
2.6 KiB
Go
// 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(), install(), to())
|
|
|
|
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/<index> 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
|
|
}
|