Herkese merhaba!

Uzun yıllardır bol miktarda kişisel zaman ve enerji harcayarak bilgimizi hepinizle paylaşıyoruz. Ancak şu andan itibaren bu blogu çalışır durumda tutabilmek için yardımınıza ihtiyacımız var. Yapmanız gereken tek şey, sitedeki reklamlardan birine tıklamak olacaktır, aksi takdirde hosting vb. masraflar nedeniyle maalesef yayından kaldırılacaktır. Teşekkürler.

Bu örnekte Golang ile bir terminal (CLI) uygulaması oluşturacağız. Komutun iki gerekli argümanı olacaktır. Argüman (flag) paketini buradan okuyabilirsiniz. Ayrıca kademeli olarak kullanıcıya üç soru soracaktır. Bir soru gizli bir değerdir, bu nedenle terminalin onu ekrana basmadığından emin olacağız. Gizli girdiler için terminal paketini kullanacağız.


Kod


package main

import (
"bufio"
"flag"
"fmt"
"os"
"strings"

"golang.org/x/crypto/ssh/terminal"
)

const usage = `Description: Login to server

Usage: %s [options]

Options:
`

var input struct {
env string
uid string
psw string
key string
pin string
}

func main() {
// Collect user input
flag.StringVar(&input.env, "env", input.env, "The environment to login - {dev|stag|prod}")
flag.StringVar(&input.uid, "uid", input.uid, "The user identifier.")
flag.Usage = func() {
_, _ = fmt.Fprintf(flag.CommandLine.Output(), usage, os.Args[0])
flag.PrintDefaults()
}
flag.Parse()

// Validate user input
validate()

// Prompt user for more input
key, err := promptPlain("What is your key?")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
input.key = key

psw, err := promptSecret("What is your password?")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
input.psw = psw

pin, err := promptPlain("What is your pin?")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
input.pin = pin

// Print user input
fmt.Printf("%+v\n", input)
}

// validate validates user input.
func validate() {
switch input.env {
case "dev", "stag", "prod":
break
default:
fmt.Println("The -env option is required.")
os.Exit(2)
}

if len(input.uid) == 0 {
fmt.Println("The -uid option is required.")
os.Exit(2)
}
}

// promptPlain prompts user for an input that is echo-ed on terminal.
func promptPlain(question string) (string, error) {
fmt.Printf(question + "\n> ")

reader := bufio.NewReader(os.Stdin)
for {
answer, err := reader.ReadString('\n')
if err != nil {
return "", err
}

answer = strings.TrimSuffix(answer, "\n")
return answer, nil
}
}

// promptSecret prompts user for an input that is not echo-ed on terminal.
func promptSecret(question string) (string, error) {
fmt.Printf(question + "\n> ")

raw, err := terminal.MakeRaw(0)
if err != nil {
return "", err
}
defer terminal.Restore(0, raw)

var (
prompt string
answer string
)

term := terminal.NewTerminal(os.Stdin, prompt)
for {
char, err := term.ReadPassword(prompt)
if err != nil {
return "", err
}
answer += char

if char == "" || char == answer {
return answer, nil
}
}
}

Kurulum


$ go build -race -o login main.go

Yardım


$ ./login --help
Description: Login to server

Usage: ./login [options]

Options:
-env string
The environment to login - {dev|stag|prod}
-uid string
The user identifier.

Testler


Hata


$ ./login
The -env option is required.

$ ./login -env dev
The -uid option is required.

Başarı


Aşağıda görebileceğiniz gibi "Şifreniz nedir?" sorusuna cevap verdim ama terminal onu yazarken ekranda göstermedi!


$ ./login -env dev -uid inanzzz
What is your key?
> my-key
What is your password?
>
What is your pin?
> my-pin

{env:dev uid:inanzzz psw:my-password key:my-key pin:my-pin}
ı