package main

import (
	"flag"
	"fmt"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"strings"
)

var options struct {
	version   bool
	namespace string
	keyfile   string
	sigfile   string
}

var key_names = [...]string{

	"id_ed25519",
	"id_ecdsa",
	"id_rsa",
	"id_dsa",
	"id_ed25519.pub",
	"id_ecdsa.pub",
	"id_rsa.pub",
	"id_dsa.pub",
}

var usage = `
  Make ssh-keygen -Y simpler

  Usage: %s COMMAND OPTION

  OPTIONS:

      -h     --help
             --version

  COMMANDS:

      sign   create signature
      check  check  signature

  HELP:

      sign     --help
      check    --help

  EXAMPLES:

      %s sign file.txt
      %s check -s file.txt.sig < file.txt

      cat file.txt | %s sign   > file.txt.sig
      cat file.txt | %s check -s file.txt.sig

      # Sign multiple files
      %s sign file1.txt file2.txt [...]

      # Use another key for signing
      %s sign -f ~/.ssh/id_rsa file.txt

      # Use a public key. Private Key for signing then comes from ssh-agent
      %s sign -f ~/.ssh/id_rsa.pub file.txt
`
var warning = `
    Missing command or option!

    %s --help

`

var Version string = "ssh-sig (ssh-tools) 1.9"

func printVersion() {
	fmt.Printf("%s\n", strings.TrimSpace(Version))
}

func main() {

	exeName := filepath.Base(os.Args[0])

	usage = strings.ReplaceAll(usage, "%s", exeName)
	warning = strings.ReplaceAll(warning, "%s", exeName)

	// Exit early if there is no ssh-keygen
	binary, err := exec.LookPath("ssh-keygen")
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	// Find SSH Keyfiles of the current user
	// Use the first we can find
	usr, _ := user.Current()
	homedir := usr.HomeDir

	for _, key_name := range key_names {
		key_file := filepath.Join(homedir, ".ssh", key_name)
		if _, err := os.Stat(key_file); !os.IsNotExist(err) {
			options.keyfile = key_file
			break // use first keyfile we find
		}
	}

	// Set of flags for subcommand sign
	sign := flag.NewFlagSet("sign", flag.ExitOnError)
	sign.StringVar(&options.namespace, "n", "file", "namespace")
	sign.StringVar(&options.keyfile, "f", options.keyfile, "Private or Public SSH Key")

	// Set of flags for subcommand check
	check := flag.NewFlagSet("check", flag.ExitOnError)
	check.StringVar(&options.sigfile, "s", "", "sigfile")
	check.StringVar(&options.namespace, "n", "file", "namespace")

	// Switch on subcommands, then apply the desired set of flags.
	if len(os.Args) < 2 {
		fmt.Fprintln(os.Stderr, warning)
		os.Exit(0)
	}

	switch os.Args[1] {
	case "--help", "-h":
		fmt.Fprintf(flag.CommandLine.Output(), usage)
		os.Exit(0)
	case "--version":
		printVersion()
		os.Exit(0)
	case "sign":
		if err := sign.Parse(os.Args[2:]); err == nil {

			args := []string{"-Y", "sign", "-n", options.namespace, "-f", options.keyfile}
			for _, file := range sign.Args() {
				args = append(args, file)
			}

			fmt.Fprintln(os.Stderr, "namespace :", options.namespace)
			fmt.Fprintln(os.Stderr, "keyfile   :", options.keyfile)
			fmt.Fprintln(os.Stderr)

			cmd := exec.Command(binary, args...)
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			cmd.Stdin = os.Stdin

			execErr := cmd.Run()

			if execErr != nil {
				panic(execErr)
			}
		}
	case "check":
		if err := check.Parse(os.Args[2:]); err == nil {

			args := []string{"-Y", "check-novalidate", "-n", options.namespace, "-s", options.sigfile}

			fmt.Fprintln(os.Stderr, "namespace :", options.namespace)
			fmt.Fprintln(os.Stderr, "sigfile   :", options.sigfile)
			fmt.Fprintln(os.Stderr)

			cmd := exec.Command(binary, args...)
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			cmd.Stdin = os.Stdin

			execErr := cmd.Run()

			if execErr != nil {
				panic(execErr)
			}
		}
	default:
		fmt.Fprintln(os.Stderr, warning)
		os.Exit(0)
	}

}
