package main

import (
	"bytes"
	"errors"
	"fmt"
	"os"

	"golang.org/x/term"
)

func askPassphrase(confirm bool) (string, error) {
	fd := int(os.Stdin.Fd()) // #nosec G115 -- stdin's fd is small; the conversion is safe

	// Refuse input that doesn't come from a real terminal (a pipe, say).
	// Without this, the "no echo" read makes no sense.
	if !term.IsTerminal(fd) {
		return "", errors.New("an interactive terminal is required for the password")
	}

	fmt.Print("password: ")
	p1, err := term.ReadPassword(fd)
	fmt.Println()
	if err != nil {
		return "", fmt.Errorf("reading the password: %w", err)
	}
	if len(p1) == 0 {
		return "", errors.New("empty password")
	}
	if !confirm {
		return string(p1), nil
	}

	fmt.Print("confirm password: ")
	p2, err := term.ReadPassword(fd)
	fmt.Println()
	if err != nil {
		return "", fmt.Errorf("reading the confirmation: %w", err)
	}
	if !bytes.Equal(p1, p2) {
		return "", errors.New("passwords do not match")
	}
	return string(p1), nil
}

func main() {

	firstUse := true // in real code, check if the password file exists or not, for example.
	pass, err := askPassphrase(firstUse)
	if err != nil {
		fmt.Fprintln(os.Stderr, "error:", err)
		os.Exit(1)
	}

	fmt.Printf("password captured %q (%d chars).\n",
		pass,
		len(pass)) // obviously you wouldn't print the password in real code.
}
