Answer to password shell prompt in golang

I am searching for a way to answer to a shell password prompt in golang.

like :

bussiere@kus:~/Workspace/rteest$ ./passwordtest.sh
Password : 

I would like to enter the password automatically with my token in golang after launching a shell command / script …

I’ve made some script that get a one time token with mfa if everything is ok (in golang). So i need to enter the tempory token to a linux password prompt.

I know that there is the expect command but i would like to compile my program to embed it and have minimal depency.

Thanks and regards

edit thks to @nevermore i’ve tried this (but it doesn’t work) : https://play.golang.org/p/Ffm3q5h636

package main

import (
    "os/exec"
    "fmt"
    "log"
    "io"
)

func main() {
    cmdb := "git"
    args := "clone https://bb@gitlab.com/bb/fzgs.git"
cmd := exec.Command(cmdb, args)
stdin, err := cmd.StdinPipe()
if err != nil {
log.Fatal(err)
}

go func() {
defer stdin.Close()
io.WriteString(stdin, "QSRDFGHJfZERTYU")
}()

out, err := cmd.CombinedOutput()
if err != nil {
log.Fatal(err)
}

fmt.Printf("%s\n", out)

}

it gives me this :

2017/05/12 20:42:36 exit status 1
exit status 1

edit bis :

    cmdb := "git"
    args := "https://bb@gitlab.com/bb/fzgs.git"
cmd := exec.Command(cmdb, "clone", args)

it asks for the password :

Password for ‘https://bb@gitlab.com’:

  • lesskey config does not get used by less pager when used with git on OSX
  • Material design icons like “\f222” altered when shared accross linux and windows environements
  • Suppress or prevent duplicate inotifywait events?
  • Moving a git repo to another server
  • SVN: Force svn daemon to run under different user
  • How to make a script to perform git pull?
  • How do I get the effect of GNU tar's --strip-components with git-archive?
  • Failing to log in via publickey ssh
  • 2 Solutions collect form web for “Answer to password shell prompt in golang”

    The problem is that you are trying to send the password before Git asks you
    to do so.

    And the way Git asks for password depends on whether credential helper is set. If the credential helper is not set, or doesn’t return a password, the user is asked for input.

    Solution #1: Include Password into URI

    In most cases (at least with Github and Bitbucket) the Git server accepts
    credentials passed via HTTPS URI, e.g. https://user:password@domain.com/repo.git.

    cmd := exec.Command("git", "clone", "https://bb:PASSWORD@gitlab.com/bb/fzgs.git")
    
    env := os.Environ()
    env = append(env, "GIT_ASKPASS=")
    cmd.Env = env
    
    var out bytes.Buffer
    cmd.Stdout = &out
    
    err := cmd.Run()
    

    Solution #2: Custom Credential Helper

    Another way is to make a credential helper script, e.g.:

    #!/bin/bash -
    printf '%s\n' 'YOUR_PASSWORD'
    

    and pass it via GIT_ASKPASS:

    cmd := exec.Command("git", "clone", "https://bb@gitlab.com/bb/fzgs.git")
    
    env := os.Environ()
    env = append(env, "GIT_ASKPASS=/path/to/fzgs-askpass.sh")
    cmd.Env = env
    
    var out bytes.Buffer
    cmd.Stdout = &out
    
    err := cmd.Run()
    

    If a user is asked for a password in their shell, you can use golang to write to the io.Writer that is os.Stdin

    Properly passing data on stdin to a command and receiving data from stdout of that command in golang

    os.Stdin is a os.File created by

    NewFile(uintptr(syscall.Stdin), "/dev/stdin"
    

    And the password prompt will be reading form this file

    You can execute ./passwordtest.sh as in your question, and then write the password to os.Stdin, and the bash script should accept the bytes written by golang as the password.


    Alternatively is actually a method for this in the exec package for the Cmd type.

    1. Use cmd to execute your shell script
    2. Input the password using stdin, or cmd.StdinPip()
    3. Read the shells output using cmd.CombinedOutput()

    Cmd represents an external command being prepared or run.

    https://golang.org/pkg/os/exec/#Cmd.StdinPipe

    cmd := exec.Command("cat")
    stdin, err := cmd.StdinPipe()
    if err != nil {
        log.Fatal(err)
    }
    
    go func() {
        defer stdin.Close()
        io.WriteString(stdin, "values written to stdin are passed to cmd's standard input")
    }()
    
    out, err := cmd.CombinedOutput()
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("%s\n", out)
    

    StdinPipe returns a pipe that will be connected to the command’s standard input when the command starts. The pipe will be closed automatically after Wait sees the command exit. A caller need only call Close to force the pipe to close sooner. For example, if the command being run will not exit until standard input is closed, the caller must close the pipe.

    Also, your cmd arguments shouldn’t combine clone and the url, try instead

    cmd := exec.Command(cmdb, "clone", url)
    
    Git Baby is a git and github fan, let's start git clone.