git2go/credentials.go

195 lines
5.6 KiB
Go
Raw Normal View History

package git
/*
#include <git2.h>
void _go_git_populate_credential_ssh_custom(git_cred_ssh_custom *cred);
*/
import "C"
import (
"crypto/rand"
"errors"
"fmt"
"unsafe"
"golang.org/x/crypto/ssh"
)
type CredType uint
2014-03-11 15:19:12 -05:00
const (
CredTypeUserpassPlaintext CredType = C.GIT_CREDTYPE_USERPASS_PLAINTEXT
CredTypeSshKey CredType = C.GIT_CREDTYPE_SSH_KEY
CredTypeSshCustom CredType = C.GIT_CREDTYPE_SSH_CUSTOM
CredTypeDefault CredType = C.GIT_CREDTYPE_DEFAULT
)
2014-03-11 15:19:12 -05:00
type Cred struct {
doNotCompare
ptr *C.git_cred
}
2014-03-11 15:19:12 -05:00
func (o *Cred) HasUsername() bool {
if C.git_cred_has_username(o.ptr) == 1 {
return true
}
return false
}
2014-03-11 15:19:12 -05:00
func (o *Cred) Type() CredType {
return (CredType)(o.ptr.credtype)
}
2014-03-11 15:19:12 -05:00
func credFromC(ptr *C.git_cred) *Cred {
return &Cred{ptr: ptr}
}
// GetUserpassPlaintext returns the plaintext username/password combination stored in the Cred.
func (o *Cred) GetUserpassPlaintext() (username, password string, err error) {
if o.Type() != CredTypeUserpassPlaintext {
err = errors.New("credential is not userpass plaintext")
return
}
plaintextCredPtr := (*C.git_cred_userpass_plaintext)(unsafe.Pointer(o.ptr))
username = C.GoString(plaintextCredPtr.username)
password = C.GoString(plaintextCredPtr.password)
return
}
// GetSSHKey returns the SSH-specific key information from the Cred object.
func (o *Cred) GetSSHKey() (username, publickey, privatekey, passphrase string, err error) {
if o.Type() != CredTypeSshKey {
err = fmt.Errorf("credential is not an SSH key: %v", o.Type())
return
}
sshKeyCredPtr := (*C.git_cred_ssh_key)(unsafe.Pointer(o.ptr))
username = C.GoString(sshKeyCredPtr.username)
publickey = C.GoString(sshKeyCredPtr.publickey)
privatekey = C.GoString(sshKeyCredPtr.privatekey)
passphrase = C.GoString(sshKeyCredPtr.passphrase)
return
}
func NewCredUsername(username string) (int, Cred) {
cred := Cred{}
cusername := C.CString(username)
ret := C.git_cred_username_new(&cred.ptr, cusername)
return int(ret), cred
}
func NewCredUserpassPlaintext(username string, password string) (int, Cred) {
2014-03-11 15:19:12 -05:00
cred := Cred{}
cusername := C.CString(username)
defer C.free(unsafe.Pointer(cusername))
cpassword := C.CString(password)
defer C.free(unsafe.Pointer(cpassword))
ret := C.git_cred_userpass_plaintext_new(&cred.ptr, cusername, cpassword)
return int(ret), cred
}
// NewCredSshKey creates new ssh credentials reading the public and private keys
// from the file system.
func NewCredSshKey(username string, publicKeyPath string, privateKeyPath string, passphrase string) (int, Cred) {
2014-03-11 15:19:12 -05:00
cred := Cred{}
cusername := C.CString(username)
defer C.free(unsafe.Pointer(cusername))
cpublickey := C.CString(publicKeyPath)
defer C.free(unsafe.Pointer(cpublickey))
cprivatekey := C.CString(privateKeyPath)
defer C.free(unsafe.Pointer(cprivatekey))
cpassphrase := C.CString(passphrase)
defer C.free(unsafe.Pointer(cpassphrase))
ret := C.git_cred_ssh_key_new(&cred.ptr, cusername, cpublickey, cprivatekey, cpassphrase)
return int(ret), cred
}
// NewCredSshKeyFromMemory creates new ssh credentials using the publicKey and privateKey
// arguments as the values for the public and private keys.
func NewCredSshKeyFromMemory(username string, publicKey string, privateKey string, passphrase string) (int, Cred) {
cred := Cred{}
cusername := C.CString(username)
defer C.free(unsafe.Pointer(cusername))
cpublickey := C.CString(publicKey)
defer C.free(unsafe.Pointer(cpublickey))
cprivatekey := C.CString(privateKey)
defer C.free(unsafe.Pointer(cprivatekey))
cpassphrase := C.CString(passphrase)
defer C.free(unsafe.Pointer(cpassphrase))
ret := C.git_cred_ssh_key_memory_new(&cred.ptr, cusername, cpublickey, cprivatekey, cpassphrase)
return int(ret), cred
}
func NewCredSshKeyFromAgent(username string) (int, Cred) {
2014-03-11 15:19:12 -05:00
cred := Cred{}
cusername := C.CString(username)
defer C.free(unsafe.Pointer(cusername))
ret := C.git_cred_ssh_key_from_agent(&cred.ptr, cusername)
return int(ret), cred
}
func NewCredDefault() (int, Cred) {
2014-03-11 15:19:12 -05:00
cred := Cred{}
ret := C.git_cred_default_new(&cred.ptr)
return int(ret), cred
}
type credentialSSHCustomData struct {
signer ssh.Signer
}
//export credentialSSHCustomFree
func credentialSSHCustomFree(cred *C.git_cred_ssh_custom) {
if cred == nil {
return
}
C.free(unsafe.Pointer(cred.username))
C.free(unsafe.Pointer(cred.publickey))
pointerHandles.Untrack(cred.payload)
C.free(unsafe.Pointer(cred))
}
//export credentialSSHSignCallback
func credentialSSHSignCallback(
errorMessage **C.char,
sig **C.uchar,
sig_len *C.size_t,
data *C.uchar,
data_len C.size_t,
handle unsafe.Pointer,
) C.int {
signer := pointerHandles.Get(handle).(*credentialSSHCustomData).signer
signature, err := signer.Sign(rand.Reader, C.GoBytes(unsafe.Pointer(data), C.int(data_len)))
if err != nil {
return setCallbackError(errorMessage, err)
}
*sig = (*C.uchar)(C.CBytes(signature.Blob))
*sig_len = C.size_t(len(signature.Blob))
return C.int(ErrorCodeOK)
}
// NewCredentialSSHKeyFromSigner creates new SSH credentials using the provided signer.
func NewCredentialSSHKeyFromSigner(username string, signer ssh.Signer) (*Cred, error) {
publicKey := signer.PublicKey().Marshal()
ccred := (*C.git_cred_ssh_custom)(C.calloc(1, C.size_t(unsafe.Sizeof(C.git_cred_ssh_custom{}))))
ccred.parent.credtype = C.GIT_CREDTYPE_SSH_CUSTOM
ccred.username = C.CString(username)
ccred.publickey = (*C.char)(C.CBytes(publicKey))
ccred.publickey_len = C.size_t(len(publicKey))
C._go_git_populate_credential_ssh_custom(ccred)
data := credentialSSHCustomData{
signer: signer,
}
ccred.payload = pointerHandles.Track(&data)
cred := Cred{
ptr: &ccred.parent,
}
return &cred, nil
}