diff --git a/Makefile b/Makefile index e2e465b..fb30b73 100644 --- a/Makefile +++ b/Makefile @@ -1,23 +1,23 @@ -.PHONY: all deps osxkeychain test +.PHONY: all deps osxkeychain test validate wincred all: test deps: - go get -t ./... go get github.com/golang/lint/golint osxkeychain: mkdir -p bin go build -o bin/docker-credential-osxkeychain osxkeychain/cmd/main_darwin.go +test: + # tests all packages except vendor + go test -v `go list ./... | grep -v /vendor/` + +validate: + go vet ./credentials ./osxkeychain + golint `go list ./... | grep -v /vendor/` + gofmt -s -l `ls **/*.go | grep -v vendor` + wincred: mkdir -p bin go build -o bin/docker-credential-wincred wincred/cmd/main_windows.go - -test: - go test -v ./... - -validate: - go vet ./... - golint ./... - gofmt -s -l . diff --git a/appveyor.yml b/appveyor.yml index 9dd4afd..62a1025 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -36,9 +36,9 @@ install: - set Path=c:\mingw64\bin;c:\go\bin;%Path% - go version - go env - - go get -v -t ./... build_script: + - go vet ./wincred - go test -v github.com/docker/docker-credential-helpers/wincred # Disable automatic tests diff --git a/osxkeychain/cmd/main_darwin.go b/osxkeychain/cmd/main_darwin.go index de434ee..becec57 100644 --- a/osxkeychain/cmd/main_darwin.go +++ b/osxkeychain/cmd/main_darwin.go @@ -1,8 +1,8 @@ package main import ( - "github.com/calavera/docker-credential-helpers/credentials" - "github.com/calavera/docker-credential-helpers/osxkeychain" + "github.com/docker/docker-credential-helpers/credentials" + "github.com/docker/docker-credential-helpers/osxkeychain" ) func main() { diff --git a/osxkeychain/osxkeychain_darwin.go b/osxkeychain/osxkeychain_darwin.go index c2eae86..4d08565 100644 --- a/osxkeychain/osxkeychain_darwin.go +++ b/osxkeychain/osxkeychain_darwin.go @@ -15,7 +15,7 @@ import ( "strings" "unsafe" - "github.com/calavera/docker-credential-helpers/credentials" + "github.com/docker/docker-credential-helpers/credentials" ) // errCredentialsNotFound is the specific error message returned by OS X diff --git a/osxkeychain/osxkeychain_darwin_test.go b/osxkeychain/osxkeychain_darwin_test.go index e6eb992..86946d6 100644 --- a/osxkeychain/osxkeychain_darwin_test.go +++ b/osxkeychain/osxkeychain_darwin_test.go @@ -3,7 +3,7 @@ package osxkeychain import ( "testing" - "github.com/calavera/docker-credential-helpers/credentials" + "github.com/docker/docker-credential-helpers/credentials" ) func TestOSXKeychainHelper(t *testing.T) { diff --git a/vendor/github.com/danieljoos/wincred/LICENSE b/vendor/github.com/danieljoos/wincred/LICENSE new file mode 100644 index 0000000..2f436f1 --- /dev/null +++ b/vendor/github.com/danieljoos/wincred/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Daniel Joos + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/danieljoos/wincred/conversion.go b/vendor/github.com/danieljoos/wincred/conversion.go new file mode 100644 index 0000000..36e67b1 --- /dev/null +++ b/vendor/github.com/danieljoos/wincred/conversion.go @@ -0,0 +1,104 @@ +package wincred + +import ( + "C" + "encoding/binary" + "reflect" + "syscall" + "time" + "unicode/utf16" + "unsafe" +) + +// Create a Go string using a pointer to a zero-terminated UTF 16 encoded string. +// See github.com/AllenDang/w32 +func utf16PtrToString(wstr *uint16) string { + if wstr != nil { + buf := make([]uint16, 0, 256) + for ptr := uintptr(unsafe.Pointer(wstr)); ; ptr += 2 { + rune := *(*uint16)(unsafe.Pointer(ptr)) + if rune == 0 { + return string(utf16.Decode(buf)) + } + buf = append(buf, rune) + } + } + + return "" +} + +// Create a byte array from a given UTF 16 char array +func utf16ToByte(wstr []uint16) (result []byte) { + result = make([]byte, len(wstr)*2) + for i, _ := range wstr { + binary.LittleEndian.PutUint16(result[(i*2):(i*2)+2], wstr[i]) + } + return +} + +// Convert the given CREDENTIAL struct to a more usable structure +func nativeToCredential(cred *nativeCREDENTIAL) (result *Credential) { + result = new(Credential) + result.Comment = utf16PtrToString(cred.Comment) + result.TargetName = utf16PtrToString(cred.TargetName) + result.TargetAlias = utf16PtrToString(cred.TargetAlias) + result.UserName = utf16PtrToString(cred.UserName) + result.LastWritten = time.Unix(0, cred.LastWritten.Nanoseconds()) + result.Persist = CredentialPersistence(cred.Persist) + result.CredentialBlob = C.GoBytes(unsafe.Pointer(cred.CredentialBlob), C.int(cred.CredentialBlobSize)) + result.Attributes = make([]CredentialAttribute, cred.AttributeCount) + attrSliceHeader := reflect.SliceHeader{ + Data: cred.Attributes, + Len: int(cred.AttributeCount), + Cap: int(cred.AttributeCount), + } + attrSlice := *(*[]nativeCREDENTIAL_ATTRIBUTE)(unsafe.Pointer(&attrSliceHeader)) + for i, attr := range attrSlice { + resultAttr := &result.Attributes[i] + resultAttr.Keyword = utf16PtrToString(attr.Keyword) + resultAttr.Value = C.GoBytes(unsafe.Pointer(attr.Value), C.int(attr.ValueSize)) + } + + return result +} + +// Convert the given Credential object back to a CREDENTIAL struct, which can be used for calling the +// Windows APIs +func nativeFromCredential(cred *Credential) (result *nativeCREDENTIAL) { + result = new(nativeCREDENTIAL) + result.Flags = 0 + result.Type = 0 + result.TargetName, _ = syscall.UTF16PtrFromString(cred.TargetName) + result.Comment, _ = syscall.UTF16PtrFromString(cred.Comment) + result.LastWritten = syscall.NsecToFiletime(cred.LastWritten.UnixNano()) + result.CredentialBlobSize = uint32(len(cred.CredentialBlob)) + if len(cred.CredentialBlob) > 0 { + result.CredentialBlob = uintptr(unsafe.Pointer(&cred.CredentialBlob[0])) + } else { + result.CredentialBlob = 0 + } + result.Persist = uint32(cred.Persist) + result.AttributeCount = uint32(len(cred.Attributes)) + attributes := make([]nativeCREDENTIAL_ATTRIBUTE, len(cred.Attributes)) + if len(attributes) > 0 { + result.Attributes = uintptr(unsafe.Pointer(&attributes[0])) + } else { + result.Attributes = 0 + } + for i, _ := range cred.Attributes { + inAttr := &cred.Attributes[i] + outAttr := &attributes[i] + outAttr.Keyword, _ = syscall.UTF16PtrFromString(inAttr.Keyword) + outAttr.Flags = 0 + outAttr.ValueSize = uint32(len(inAttr.Value)) + if len(inAttr.Value) > 0 { + outAttr.Value = uintptr(unsafe.Pointer(&inAttr.Value[0])) + } else { + outAttr.Value = 0 + } + } + result.TargetAlias, _ = syscall.UTF16PtrFromString(cred.TargetAlias) + result.UserName, _ = syscall.UTF16PtrFromString(cred.UserName) + + return +} diff --git a/vendor/github.com/danieljoos/wincred/native.go b/vendor/github.com/danieljoos/wincred/native.go new file mode 100644 index 0000000..16e91ad --- /dev/null +++ b/vendor/github.com/danieljoos/wincred/native.go @@ -0,0 +1,99 @@ +package wincred + +import ( + "syscall" + "unsafe" +) + +var ( + modadvapi32 = syscall.NewLazyDLL("advapi32.dll") + + procCredRead = modadvapi32.NewProc("CredReadW") + procCredWrite = modadvapi32.NewProc("CredWriteW") + procCredDelete = modadvapi32.NewProc("CredDeleteW") + procCredFree = modadvapi32.NewProc("CredFree") +) + +// http://msdn.microsoft.com/en-us/library/windows/desktop/aa374788(v=vs.85).aspx +type nativeCREDENTIAL struct { + Flags uint32 + Type uint32 + TargetName *uint16 + Comment *uint16 + LastWritten syscall.Filetime + CredentialBlobSize uint32 + CredentialBlob uintptr + Persist uint32 + AttributeCount uint32 + Attributes uintptr + TargetAlias *uint16 + UserName *uint16 +} + +// http://msdn.microsoft.com/en-us/library/windows/desktop/aa374790(v=vs.85).aspx +type nativeCREDENTIAL_ATTRIBUTE struct { + Keyword *uint16 + Flags uint32 + ValueSize uint32 + Value uintptr +} + +// http://msdn.microsoft.com/en-us/library/windows/desktop/aa374788(v=vs.85).aspx +type nativeCRED_TYPE uint32 + +const ( + naCRED_TYPE_GENERIC nativeCRED_TYPE = 0x1 + naCRED_TYPE_DOMAIN_PASSWORD nativeCRED_TYPE = 0x2 + naCRED_TYPE_DOMAIN_CERTIFICATE nativeCRED_TYPE = 0x3 + naCRED_TYPE_DOMAIN_VISIBLE_PASSWORD nativeCRED_TYPE = 0x4 + naCRED_TYPE_GENERIC_CERTIFICATE nativeCRED_TYPE = 0x5 + naCRED_TYPE_DOMAIN_EXTENDED nativeCRED_TYPE = 0x6 +) + +// http://msdn.microsoft.com/en-us/library/windows/desktop/aa374804(v=vs.85).aspx +func nativeCredRead(targetName string, typ nativeCRED_TYPE) (*Credential, error) { + var pcred uintptr + targetNamePtr, _ := syscall.UTF16PtrFromString(targetName) + ret, _, err := procCredRead.Call( + uintptr(unsafe.Pointer(targetNamePtr)), + uintptr(typ), + 0, + uintptr(unsafe.Pointer(&pcred)), + ) + if ret == 0 { + return nil, err + } + defer procCredFree.Call(pcred) + + return nativeToCredential((*nativeCREDENTIAL)(unsafe.Pointer(pcred))), nil +} + +// http://msdn.microsoft.com/en-us/library/windows/desktop/aa375187(v=vs.85).aspx +func nativeCredWrite(cred *Credential, typ nativeCRED_TYPE) error { + ncred := nativeFromCredential(cred) + ncred.Type = uint32(typ) + ret, _, err := procCredWrite.Call( + uintptr(unsafe.Pointer(ncred)), + 0, + ) + if ret == 0 { + return err + } + + return nil +} + +// http://msdn.microsoft.com/en-us/library/windows/desktop/aa374787(v=vs.85).aspx +func nativeCredDelete(cred *Credential, typ nativeCRED_TYPE) error { + targetNamePtr, _ := syscall.UTF16PtrFromString(cred.TargetName) + ret, _, err := procCredDelete.Call( + uintptr(unsafe.Pointer(targetNamePtr)), + uintptr(typ), + 0, + ) + if ret == 0 { + return err + } + + return nil +} diff --git a/vendor/github.com/danieljoos/wincred/types.go b/vendor/github.com/danieljoos/wincred/types.go new file mode 100644 index 0000000..a067992 --- /dev/null +++ b/vendor/github.com/danieljoos/wincred/types.go @@ -0,0 +1,37 @@ +package wincred + +import ( + "time" +) + +type CredentialPersistence uint32 + +const ( + PersistSession CredentialPersistence = 0x1 + PersistLocalMachine CredentialPersistence = 0x2 + PersistEnterprise CredentialPersistence = 0x3 +) + +type CredentialAttribute struct { + Keyword string + Value []byte +} + +type Credential struct { + TargetName string + Comment string + LastWritten time.Time + CredentialBlob []byte + Attributes []CredentialAttribute + TargetAlias string + UserName string + Persist CredentialPersistence +} + +type GenericCredential struct { + Credential +} + +type DomainPassword struct { + Credential +} diff --git a/vendor/github.com/danieljoos/wincred/wincred.go b/vendor/github.com/danieljoos/wincred/wincred.go new file mode 100644 index 0000000..bdcf609 --- /dev/null +++ b/vendor/github.com/danieljoos/wincred/wincred.go @@ -0,0 +1,69 @@ +package wincred + +import ( + "syscall" +) + +// Get the generic credential with the given name from Windows credential manager +func GetGenericCredential(targetName string) (*GenericCredential, error) { + cred, err := nativeCredRead(targetName, naCRED_TYPE_GENERIC) + if cred != nil { + return &GenericCredential{*cred}, err + } + return nil, err +} + +// Create a new generic credential with the given name +func NewGenericCredential(targetName string) (result *GenericCredential) { + result = new(GenericCredential) + result.TargetName = targetName + result.Persist = PersistLocalMachine + return +} + +// Persist the credential to Windows credential manager +func (t *GenericCredential) Write() (err error) { + err = nativeCredWrite(&t.Credential, naCRED_TYPE_GENERIC) + return +} + +// Delete the credential from Windows credential manager +func (t *GenericCredential) Delete() (err error) { + err = nativeCredDelete(&t.Credential, naCRED_TYPE_GENERIC) + return +} + +// Get the domain password credential with the given target host name +func GetDomainPassword(targetName string) (*DomainPassword, error) { + cred, err := nativeCredRead(targetName, naCRED_TYPE_DOMAIN_PASSWORD) + if cred != nil { + return &DomainPassword{*cred}, err + } + return nil, err +} + +// Create a new domain password credential used for login to the given target host name +func NewDomainPassword(targetName string) (result *DomainPassword) { + result = new(DomainPassword) + result.TargetName = targetName + result.Persist = PersistLocalMachine + return +} + +// Persist the domain password credential to Windows credential manager +func (t *DomainPassword) Write() (err error) { + err = nativeCredWrite(&t.Credential, naCRED_TYPE_DOMAIN_PASSWORD) + return +} + +// Delete the domain password credential from Windows credential manager +func (t *DomainPassword) Delete() (err error) { + err = nativeCredDelete(&t.Credential, naCRED_TYPE_DOMAIN_PASSWORD) + return +} + +// Set the CredentialBlob field of a domain password credential +// using an UTF16 encoded password string +func (t *DomainPassword) SetPassword(pw string) { + t.CredentialBlob = utf16ToByte(syscall.StringToUTF16(pw)) +}