gitcredentialhelper

package module
v0.0.0-...-e7f4282 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 7, 2019 License: GPL-3.0 Imports: 19 Imported by: 2

README

go-git-http-credentials-helper

A Go library that adds a secure password/username ask function to a git push/pull/fetch command over http

The problem:

When executing git fetch/push/pull it might ask for credentials but git craches when it detects it's ran in a tty.
This libary fixes that problem and makes it possible to fillin the username/password fields if there they are asked for.

How to use:

// 1. Import the package:
import (
  gitcredentialhelper "github.com/mjarkk/go-git-http-credentials-helper"
)

// 2: Add the SetupClient to the top of the application
// IMPORTANT: Do not write to stdout before this function!!
func main() {
  gitcredentialhelper.SetupClient()
}

// 3: run a git command that needs credentials
func pushToTheRepo() {
  // Create a exec.Cmd
  cmd := exec.Command("git", "push")
  
  // The output is the same as cmd.CombinedOutput()
  out, err := gitcredentialhelper.Run(cmd, func(question string) string {
    // question is "username" or "password"
    // and it expects to get back the username or password depending on the question
    fmt.Println("git asked for:", question)
    return "my username or password"
  })
  
  // ....
}

If git commands take forever you might need to set the Options argument:

// ....

// "your-app-name" needs to be the appname as snown in the terminal title or in task manager this does NOT contain any / or .
options := gitcredentialhelper.Options{AppName: "your-app-name"}
gitcredentialhelper.Run(cmd, askFunction, options)

// ....

If you have a logger and want to log more errors:

func main() {
  gitcredentialhelper.SetupClient(func(err error) {
    // DO NOT PRINT THE ERROR!
    // If you do that the error will be seen as password/username for git
    log.Error(err)
  })
}

How it works:

  1. Your program calles git push in a http repo
  2. This libary creates a webserver for username/password questions and adds the needed shell variables to the process
  3. Git sees the GIT_ASKPASS and runs your program with as arugment: username for repo "https://example.com/you/yourprogram"
  4. Now the proccess tree looks a bit like this: yourProgram -> git -> yourProgram (in reality this look more like ... -> git -> git -> git -> ...)
  5. This libary detects if yourProgram is started by git and if so runs it's own startup script (this is the SetupClient() function)
  6. This libary will create a keypair and do a network request to the main program that spawned git in the first place
  7. The main program will pickup the network request and check if it is not a fake request. After that it will ask the ask function for a password/username and will encrypt the data with a public key from yourProgram and send the encrypted message back to the program that was created by git.
  8. yourProgram spawned by git will decrypt the message and printout the contents of the message, after that it will exit the program.
    (There are still some things i've not mentioned but those things are mostly useless to know)

Q and A:

Why all this if you can just use a pty?

Mostly because of Windows.
Windows does have a dll to create a PTY but there are no inplementations yet and i would need to included the dll because a lot of users don't have the dll.
Also PTY support on the Windows 10 subsystem (linux on windows) as non-root user is completely broken.
Beside all of that this is the offical way to use external programs for git credentials.

Is this secure?

TL;DR Yes.
The long answer is no, it's probebly possible to break this libary. Though i could not succeed in breaking this and if someone did break it would be still a 50% change to get any input due to security measures.
It's easier for someone to add a keylogger in your terminal than to break this.

Known issues:

  • The credential manager on windows can break this if the popup is closed by the user. As user the best thing to do in that case is to remove the credential manager from git: git config --system --unset credential.helper
  • This does not work with the go run ...

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Run

func Run(cmd *exec.Cmd, ask func(string) string, potentialOptions ...Options) ([]byte, error)

Run runs git commands that need credentials ask() gets executed when git needs credentials The ask argument will be "username" or "password"

func SetupClient

func SetupClient(logger ...func(error))

SetupClient sets up the client BEFORE THIS FUNCTION RUNS THERE CAN'T BE ANY PRINTING OTHERWHISE THIS LIBARY WON'T WORK!

Types

type EncryptedMessage

type EncryptedMessage struct {
	EncryptedKey []byte
	Data         []byte
}

EncryptedMessage is what a encrypted message looks like The key is the encryption key encrypted using the public key of the sender The Data is the actual data

type InputQuestion

type InputQuestion struct {
	PublicKey string
	Question  string
	Listener  string
}

InputQuestion is the data that is send to Host from the Client

type Listener

type Listener int

Listener represents all server functions

func (*Listener) Input

func (l *Listener) Input(in InputQuestion, out *EncryptedMessage) error

Input is the function that response on a credentials question from the client

type Options

type Options struct {
	AppName string
}

Options are the argument options for run

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL