merge master
This commit is contained in:
commit
ce18a1d11f
287
lfs/client.go
287
lfs/client.go
@ -55,18 +55,18 @@ type objectResource struct {
|
|||||||
Error *objectError `json:"error,omitempty"`
|
Error *objectError `json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *objectResource) NewRequest(relation, method string) (*http.Request, Creds, error) {
|
func (o *objectResource) NewRequest(relation, method string) (*http.Request, error) {
|
||||||
rel, ok := o.Rel(relation)
|
rel, ok := o.Rel(relation)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, nil, errors.New("relation does not exist")
|
return nil, errors.New("relation does not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
req, creds, err := newClientRequest(method, rel.Href, rel.Header)
|
req, err := newClientRequest(method, rel.Href, rel.Header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return req, creds, nil
|
return req, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *objectResource) Rel(name string) (*linkRelation, bool) {
|
func (o *objectResource) Rel(name string) (*linkRelation, bool) {
|
||||||
@ -105,23 +105,22 @@ func (e *ClientError) Error() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Download(oid string) (io.ReadCloser, int64, error) {
|
func Download(oid string) (io.ReadCloser, int64, error) {
|
||||||
req, creds, err := newApiRequest("GET", oid)
|
req, err := newApiRequest("GET", oid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, Error(err)
|
return nil, 0, Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
res, obj, err := doApiRequest(req, creds)
|
res, obj, err := doLegacyApiRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
LogTransfer("lfs.api.download", res)
|
LogTransfer("lfs.api.download", res)
|
||||||
|
req, err = obj.NewRequest("download", "GET")
|
||||||
req, creds, err = obj.NewRequest("download", "GET")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, Error(err)
|
return nil, 0, Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err = doHttpRequest(req, creds)
|
res, err = doStorageRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
@ -135,18 +134,18 @@ type byteCloser struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func DownloadCheck(oid string) (*objectResource, error) {
|
func DownloadCheck(oid string) (*objectResource, error) {
|
||||||
req, creds, err := newApiRequest("GET", oid)
|
req, err := newApiRequest("GET", oid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, Error(err)
|
return nil, Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
res, obj, err := doApiRequest(req, creds)
|
res, obj, err := doLegacyApiRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
LogTransfer("lfs.api.download", res)
|
LogTransfer("lfs.api.download", res)
|
||||||
|
|
||||||
_, _, err = obj.NewRequest("download", "GET")
|
_, err = obj.NewRequest("download", "GET")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, Error(err)
|
return nil, Error(err)
|
||||||
}
|
}
|
||||||
@ -155,12 +154,12 @@ func DownloadCheck(oid string) (*objectResource, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func DownloadObject(obj *objectResource) (io.ReadCloser, int64, error) {
|
func DownloadObject(obj *objectResource) (io.ReadCloser, int64, error) {
|
||||||
req, creds, err := obj.NewRequest("download", "GET")
|
req, err := obj.NewRequest("download", "GET")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, Error(err)
|
return nil, 0, Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := doHttpRequest(req, creds)
|
res, err := doStorageRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
@ -185,7 +184,7 @@ func Batch(objects []*objectResource, operation string) ([]*objectResource, erro
|
|||||||
return nil, Error(err)
|
return nil, Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
req, creds, err := newBatchApiRequest()
|
req, err := newBatchApiRequest()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, Error(err)
|
return nil, Error(err)
|
||||||
}
|
}
|
||||||
@ -196,7 +195,8 @@ func Batch(objects []*objectResource, operation string) ([]*objectResource, erro
|
|||||||
req.Body = &byteCloser{bytes.NewReader(by)}
|
req.Body = &byteCloser{bytes.NewReader(by)}
|
||||||
|
|
||||||
tracerx.Printf("api: batch %d files", len(objects))
|
tracerx.Printf("api: batch %d files", len(objects))
|
||||||
res, objs, err := doApiBatchRequest(req, creds)
|
|
||||||
|
res, objs, err := doApiBatchRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if res == nil {
|
if res == nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -241,7 +241,7 @@ func UploadCheck(oidPath string) (*objectResource, error) {
|
|||||||
return nil, Error(err)
|
return nil, Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
req, creds, err := newApiRequest("POST", oid)
|
req, err := newApiRequest("POST", oid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, Error(err)
|
return nil, Error(err)
|
||||||
}
|
}
|
||||||
@ -252,7 +252,7 @@ func UploadCheck(oidPath string) (*objectResource, error) {
|
|||||||
req.Body = &byteCloser{bytes.NewReader(by)}
|
req.Body = &byteCloser{bytes.NewReader(by)}
|
||||||
|
|
||||||
tracerx.Printf("api: uploading (%s)", oid)
|
tracerx.Printf("api: uploading (%s)", oid)
|
||||||
res, obj, err := doApiRequest(req, creds)
|
res, obj, err := doLegacyApiRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -290,7 +290,7 @@ func UploadObject(o *objectResource, cb CopyCallback) error {
|
|||||||
Reader: file,
|
Reader: file,
|
||||||
}
|
}
|
||||||
|
|
||||||
req, creds, err := o.NewRequest("upload", "PUT")
|
req, err := o.NewRequest("upload", "PUT")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Error(err)
|
return Error(err)
|
||||||
}
|
}
|
||||||
@ -298,16 +298,17 @@ func UploadObject(o *objectResource, cb CopyCallback) error {
|
|||||||
if len(req.Header.Get("Content-Type")) == 0 {
|
if len(req.Header.Get("Content-Type")) == 0 {
|
||||||
req.Header.Set("Content-Type", "application/octet-stream")
|
req.Header.Set("Content-Type", "application/octet-stream")
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Header.Get("Transfer-Encoding") == "chunked" {
|
if req.Header.Get("Transfer-Encoding") == "chunked" {
|
||||||
req.TransferEncoding = []string{"chunked"}
|
req.TransferEncoding = []string{"chunked"}
|
||||||
} else {
|
} else {
|
||||||
req.Header.Set("Content-Length", strconv.FormatInt(o.Size, 10))
|
req.Header.Set("Content-Length", strconv.FormatInt(o.Size, 10))
|
||||||
}
|
}
|
||||||
req.ContentLength = o.Size
|
|
||||||
|
|
||||||
|
req.ContentLength = o.Size
|
||||||
req.Body = ioutil.NopCloser(reader)
|
req.Body = ioutil.NopCloser(reader)
|
||||||
|
|
||||||
res, err := doHttpRequest(req, creds)
|
res, err := doStorageRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -324,7 +325,7 @@ func UploadObject(o *objectResource, cb CopyCallback) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
req, creds, err = o.NewRequest("verify", "POST")
|
req, err = o.NewRequest("verify", "POST")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Error(err)
|
return Error(err)
|
||||||
}
|
}
|
||||||
@ -338,7 +339,7 @@ func UploadObject(o *objectResource, cb CopyCallback) error {
|
|||||||
req.Header.Set("Content-Length", strconv.Itoa(len(by)))
|
req.Header.Set("Content-Length", strconv.Itoa(len(by)))
|
||||||
req.ContentLength = int64(len(by))
|
req.ContentLength = int64(len(by))
|
||||||
req.Body = ioutil.NopCloser(bytes.NewReader(by))
|
req.Body = ioutil.NopCloser(bytes.NewReader(by))
|
||||||
res, err = doHttpRequest(req, creds)
|
res, err = doAPIRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -350,6 +351,72 @@ func UploadObject(o *objectResource, cb CopyCallback) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// doLegacyApiRequest runs the request to the LFS legacy API.
|
||||||
|
func doLegacyApiRequest(req *http.Request) (*http.Response, *objectResource, error) {
|
||||||
|
via := make([]*http.Request, 0, 4)
|
||||||
|
res, err := doApiRequestWithRedirects(req, via, true)
|
||||||
|
if err != nil {
|
||||||
|
return res, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
obj := &objectResource{}
|
||||||
|
err = decodeApiResponse(res, obj)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
setErrorResponseContext(err, res)
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, obj, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// doApiBatchRequest runs the request to the LFS batch API. If the API returns a
|
||||||
|
// 401, the repo will be marked as having private access and the request will be
|
||||||
|
// re-run. When the repo is marked as having private access, credentials will
|
||||||
|
// be retrieved.
|
||||||
|
func doApiBatchRequest(req *http.Request) (*http.Response, []*objectResource, error) {
|
||||||
|
res, err := doAPIRequest(req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return res, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var objs map[string][]*objectResource
|
||||||
|
err = decodeApiResponse(res, &objs)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
setErrorResponseContext(err, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, objs["objects"], err
|
||||||
|
}
|
||||||
|
|
||||||
|
// doStorageREquest runs the request to the storage API from a link provided by
|
||||||
|
// the "actions" or "_links" properties an LFS API response.
|
||||||
|
func doStorageRequest(req *http.Request) (*http.Response, error) {
|
||||||
|
creds, err := getCreds(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return doHttpRequest(req, creds)
|
||||||
|
}
|
||||||
|
|
||||||
|
// doAPIRequest runs the request to the LFS API, without parsing the response
|
||||||
|
// body. If the API returns a 401, the repo will be marked as having private
|
||||||
|
// access and the request will be re-run. When the repo is marked as having
|
||||||
|
// private access, credentials will be retrieved.
|
||||||
|
func doAPIRequest(req *http.Request) (*http.Response, error) {
|
||||||
|
via := make([]*http.Request, 0, 4)
|
||||||
|
useCreds := true
|
||||||
|
if req.Method == "GET" || req.Method == "HEAD" {
|
||||||
|
useCreds = Config.PrivateAccess()
|
||||||
|
}
|
||||||
|
return doApiRequestWithRedirects(req, via, useCreds)
|
||||||
|
}
|
||||||
|
|
||||||
|
// doHttpRequest runs the given HTTP request. LFS or Storage API requests should
|
||||||
|
// use doApiBatchRequest() or doStorageRequest() instead.
|
||||||
func doHttpRequest(req *http.Request, creds Creds) (*http.Response, error) {
|
func doHttpRequest(req *http.Request, creds Creds) (*http.Response, error) {
|
||||||
res, err := Config.HttpClient().Do(req)
|
res, err := Config.HttpClient().Do(req)
|
||||||
if res == nil {
|
if res == nil {
|
||||||
@ -364,8 +431,7 @@ func doHttpRequest(req *http.Request, creds Creds) (*http.Response, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
err = Errorf(err, "Error for %s %s", res.Request.Method, res.Request.URL)
|
err = Errorf(err, "Error for %s %s", res.Request.Method, res.Request.URL)
|
||||||
} else {
|
} else {
|
||||||
saveCredentials(creds, res)
|
err = handleResponse(res, creds)
|
||||||
err = handleResponse(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -379,7 +445,16 @@ func doHttpRequest(req *http.Request, creds Creds) (*http.Response, error) {
|
|||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func doApiRequestWithRedirects(req *http.Request, creds Creds, via []*http.Request) (*http.Response, error) {
|
func doApiRequestWithRedirects(req *http.Request, via []*http.Request, useCreds bool) (*http.Response, error) {
|
||||||
|
var creds Creds
|
||||||
|
if useCreds {
|
||||||
|
c, err := getCredsForAPI(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
creds = c
|
||||||
|
}
|
||||||
|
|
||||||
res, err := doHttpRequest(req, creds)
|
res, err := doHttpRequest(req, creds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
@ -393,7 +468,7 @@ func doApiRequestWithRedirects(req *http.Request, creds Creds, via []*http.Reque
|
|||||||
redirectTo = locurl.String()
|
redirectTo = locurl.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
redirectedReq, redirectedCreds, err := newClientRequest(req.Method, redirectTo, nil)
|
redirectedReq, err := newClientRequest(req.Method, redirectTo, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, Errorf(err, err.Error())
|
return res, Errorf(err, err.Error())
|
||||||
}
|
}
|
||||||
@ -421,53 +496,15 @@ func doApiRequestWithRedirects(req *http.Request, creds Creds, via []*http.Reque
|
|||||||
return res, Errorf(err, err.Error())
|
return res, Errorf(err, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return doApiRequestWithRedirects(redirectedReq, redirectedCreds, via)
|
return doApiRequestWithRedirects(redirectedReq, via, useCreds)
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func doApiRequest(req *http.Request, creds Creds) (*http.Response, *objectResource, error) {
|
func handleResponse(res *http.Response, creds Creds) error {
|
||||||
via := make([]*http.Request, 0, 4)
|
saveCredentials(creds, res)
|
||||||
res, err := doApiRequestWithRedirects(req, creds, via)
|
|
||||||
if err != nil {
|
|
||||||
return res, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
obj := &objectResource{}
|
|
||||||
err = decodeApiResponse(res, obj)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
setErrorResponseContext(err, res)
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, obj, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// doApiBatchRequest runs the request to the batch API. If the API returns a 401,
|
|
||||||
// the repo will be marked as having private access and the request will be
|
|
||||||
// re-run. When the repo is marked as having private access, credentials will
|
|
||||||
// be retrieved.
|
|
||||||
func doApiBatchRequest(req *http.Request, creds Creds) (*http.Response, []*objectResource, error) {
|
|
||||||
via := make([]*http.Request, 0, 4)
|
|
||||||
res, err := doApiRequestWithRedirects(req, creds, via)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return res, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var objs map[string][]*objectResource
|
|
||||||
err = decodeApiResponse(res, &objs)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
setErrorResponseContext(err, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, objs["objects"], err
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleResponse(res *http.Response) error {
|
|
||||||
if res.StatusCode < 400 {
|
if res.StatusCode < 400 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -525,19 +562,7 @@ func defaultError(res *http.Response) error {
|
|||||||
return Error(fmt.Errorf(msgFmt, res.Request.URL))
|
return Error(fmt.Errorf(msgFmt, res.Request.URL))
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveCredentials(creds Creds, res *http.Response) {
|
func newApiRequest(method, oid string) (*http.Request, error) {
|
||||||
if creds == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if res.StatusCode < 300 {
|
|
||||||
execCreds(creds, "approve")
|
|
||||||
} else if res.StatusCode == 401 {
|
|
||||||
execCreds(creds, "reject")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newApiRequest(method, oid string) (*http.Request, Creds, error) {
|
|
||||||
endpoint := Config.Endpoint()
|
endpoint := Config.Endpoint()
|
||||||
objectOid := oid
|
objectOid := oid
|
||||||
operation := "download"
|
operation := "download"
|
||||||
@ -561,22 +586,22 @@ func newApiRequest(method, oid string) (*http.Request, Creds, error) {
|
|||||||
|
|
||||||
u, err := ObjectUrl(endpoint, objectOid)
|
u, err := ObjectUrl(endpoint, objectOid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
req, creds, err := newClientRequest(method, u.String(), res.Header)
|
req, err := newClientRequest(method, u.String(), res.Header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("Accept", mediaType)
|
req.Header.Set("Accept", mediaType)
|
||||||
return req, creds, nil
|
return req, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newClientRequest(method, rawurl string, header map[string]string) (*http.Request, Creds, error) {
|
func newClientRequest(method, rawurl string, header map[string]string) (*http.Request, error) {
|
||||||
req, err := http.NewRequest(method, rawurl, nil)
|
req, err := http.NewRequest(method, rawurl, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, value := range header {
|
for key, value := range header {
|
||||||
@ -584,15 +609,11 @@ func newClientRequest(method, rawurl string, header map[string]string) (*http.Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("User-Agent", UserAgent)
|
req.Header.Set("User-Agent", UserAgent)
|
||||||
creds, err := getCreds(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return req, creds, nil
|
return req, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBatchApiRequest() (*http.Request, Creds, error) {
|
func newBatchApiRequest() (*http.Request, error) {
|
||||||
endpoint := Config.Endpoint()
|
endpoint := Config.Endpoint()
|
||||||
|
|
||||||
res, err := sshAuthenticate(endpoint, "download", "")
|
res, err := sshAuthenticate(endpoint, "download", "")
|
||||||
@ -608,12 +629,12 @@ func newBatchApiRequest() (*http.Request, Creds, error) {
|
|||||||
|
|
||||||
u, err := ObjectUrl(endpoint, "batch")
|
u, err := ObjectUrl(endpoint, "batch")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
req, creds, err := newBatchClientRequest("POST", u.String())
|
req, err := newBatchClientRequest("POST", u.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("Accept", mediaType)
|
req.Header.Set("Accept", mediaType)
|
||||||
@ -623,78 +644,18 @@ func newBatchApiRequest() (*http.Request, Creds, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return req, creds, nil
|
return req, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBatchClientRequest(method, rawurl string) (*http.Request, Creds, error) {
|
func newBatchClientRequest(method, rawurl string) (*http.Request, error) {
|
||||||
req, err := http.NewRequest(method, rawurl, nil)
|
req, err := http.NewRequest(method, rawurl, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("User-Agent", UserAgent)
|
req.Header.Set("User-Agent", UserAgent)
|
||||||
|
|
||||||
// Get the creds if we're private
|
return req, nil
|
||||||
if Config.PrivateAccess() {
|
|
||||||
// The PrivateAccess() check can be pushed down and this block simplified
|
|
||||||
// once everything goes through the batch endpoint.
|
|
||||||
creds, err := getCreds(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return req, creds, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return req, nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCreds(req *http.Request) (Creds, error) {
|
|
||||||
if len(req.Header.Get("Authorization")) > 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
apiUrl, err := Config.ObjectUrl("")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.URL.Scheme != apiUrl.Scheme ||
|
|
||||||
req.URL.Host != apiUrl.Host {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if setRequestAuthFromUrl(req, apiUrl) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
credsUrl := apiUrl
|
|
||||||
if len(Config.CurrentRemote) > 0 {
|
|
||||||
if u, ok := Config.GitConfig("remote." + Config.CurrentRemote + ".url"); ok {
|
|
||||||
gitRemoteUrl, err := url.Parse(u)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if gitRemoteUrl.Scheme == apiUrl.Scheme &&
|
|
||||||
gitRemoteUrl.Host == apiUrl.Host {
|
|
||||||
|
|
||||||
if setRequestAuthFromUrl(req, gitRemoteUrl) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
credsUrl = gitRemoteUrl
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
creds, err := credentials(credsUrl)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
setRequestAuth(req, creds["username"], creds["password"])
|
|
||||||
return creds, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func setRequestAuthFromUrl(req *http.Request, u *url.URL) bool {
|
func setRequestAuthFromUrl(req *http.Request, u *url.URL) bool {
|
||||||
@ -710,6 +671,10 @@ func setRequestAuthFromUrl(req *http.Request, u *url.URL) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setRequestAuth(req *http.Request, user, pass string) {
|
func setRequestAuth(req *http.Request, user, pass string) {
|
||||||
|
if len(user) == 0 && len(pass) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
token := fmt.Sprintf("%s:%s", user, pass)
|
token := fmt.Sprintf("%s:%s", user, pass)
|
||||||
auth := "Basic " + base64.URLEncoding.EncodeToString([]byte(token))
|
auth := "Basic " + base64.URLEncoding.EncodeToString([]byte(token))
|
||||||
req.Header.Set("Authorization", auth)
|
req.Header.Set("Authorization", auth)
|
||||||
|
@ -13,7 +13,7 @@ import (
|
|||||||
func TestSuccessStatus(t *testing.T) {
|
func TestSuccessStatus(t *testing.T) {
|
||||||
for _, status := range []int{200, 201, 202} {
|
for _, status := range []int{200, 201, 202} {
|
||||||
res := &http.Response{StatusCode: status}
|
res := &http.Response{StatusCode: status}
|
||||||
if err := handleResponse(res); err != nil {
|
if err := handleResponse(res, nil); err != nil {
|
||||||
t.Errorf("Unexpected error for HTTP %d: %s", status, err.Error())
|
t.Errorf("Unexpected error for HTTP %d: %s", status, err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,7 +59,7 @@ func TestErrorStatusWithCustomMessage(t *testing.T) {
|
|||||||
}
|
}
|
||||||
res.Header.Set("Content-Type", "application/vnd.git-lfs+json; charset=utf-8")
|
res.Header.Set("Content-Type", "application/vnd.git-lfs+json; charset=utf-8")
|
||||||
|
|
||||||
err = handleResponse(res)
|
err = handleResponse(res, nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("No error from HTTP %d", status)
|
t.Errorf("No error from HTTP %d", status)
|
||||||
continue
|
continue
|
||||||
@ -121,7 +121,7 @@ func TestErrorStatusWithDefaultMessage(t *testing.T) {
|
|||||||
// purposely wrong content type so it falls back to default
|
// purposely wrong content type so it falls back to default
|
||||||
res.Header.Set("Content-Type", "application/vnd.git-lfs+json2")
|
res.Header.Set("Content-Type", "application/vnd.git-lfs+json2")
|
||||||
|
|
||||||
err = handleResponse(res)
|
err = handleResponse(res, nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("No error from HTTP %d", status)
|
t.Errorf("No error from HTTP %d", status)
|
||||||
continue
|
continue
|
||||||
|
@ -53,6 +53,7 @@ type Configuration struct {
|
|||||||
|
|
||||||
loading sync.Mutex // guards initialization of gitConfig and remotes
|
loading sync.Mutex // guards initialization of gitConfig and remotes
|
||||||
gitConfig map[string]string
|
gitConfig map[string]string
|
||||||
|
origConfig map[string]string
|
||||||
remotes []string
|
remotes []string
|
||||||
extensions map[string]Extension
|
extensions map[string]Extension
|
||||||
fetchIncludePaths []string
|
fetchIncludePaths []string
|
||||||
@ -234,11 +235,6 @@ func (c *Configuration) GitConfig(key string) (string, bool) {
|
|||||||
return value, ok
|
return value, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Configuration) SetConfig(key, value string) {
|
|
||||||
c.loadGitConfig()
|
|
||||||
c.gitConfig[key] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Configuration) ObjectUrl(oid string) (*url.URL, error) {
|
func (c *Configuration) ObjectUrl(oid string) (*url.URL, error) {
|
||||||
return ObjectUrl(c.Endpoint(), oid)
|
return ObjectUrl(c.Endpoint(), oid)
|
||||||
}
|
}
|
||||||
@ -290,12 +286,12 @@ func (c *Configuration) FetchPruneConfig() *FetchPruneConfig {
|
|||||||
return c.fetchPruneConfig
|
return c.fetchPruneConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Configuration) loadGitConfig() {
|
func (c *Configuration) loadGitConfig() bool {
|
||||||
c.loading.Lock()
|
c.loading.Lock()
|
||||||
defer c.loading.Unlock()
|
defer c.loading.Unlock()
|
||||||
|
|
||||||
if c.gitConfig != nil {
|
if c.gitConfig != nil {
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
uniqRemotes := make(map[string]bool)
|
uniqRemotes := make(map[string]bool)
|
||||||
@ -373,4 +369,6 @@ func (c *Configuration) loadGitConfig() {
|
|||||||
}
|
}
|
||||||
c.remotes = append(c.remotes, remote)
|
c.remotes = append(c.remotes, remote)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
@ -184,6 +184,7 @@ func TestBareHTTPEndpointAddsLfsSuffix(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestObjectUrl(t *testing.T) {
|
func TestObjectUrl(t *testing.T) {
|
||||||
|
defer Config.ResetConfig()
|
||||||
tests := map[string]string{
|
tests := map[string]string{
|
||||||
"http://example.com": "http://example.com/objects/oid",
|
"http://example.com": "http://example.com/objects/oid",
|
||||||
"http://example.com/": "http://example.com/objects/oid",
|
"http://example.com/": "http://example.com/objects/oid",
|
||||||
@ -205,6 +206,8 @@ func TestObjectUrl(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestObjectsUrl(t *testing.T) {
|
func TestObjectsUrl(t *testing.T) {
|
||||||
|
defer Config.ResetConfig()
|
||||||
|
|
||||||
tests := map[string]string{
|
tests := map[string]string{
|
||||||
"http://example.com": "http://example.com/objects",
|
"http://example.com": "http://example.com/objects",
|
||||||
"http://example.com/": "http://example.com/objects",
|
"http://example.com/": "http://example.com/objects",
|
||||||
@ -391,6 +394,7 @@ func TestLoadInvalidExtension(t *testing.T) {
|
|||||||
assert.Equal(t, "", ext.Smudge)
|
assert.Equal(t, "", ext.Smudge)
|
||||||
assert.Equal(t, 0, ext.Priority)
|
assert.Equal(t, 0, ext.Priority)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFetchPruneConfigDefault(t *testing.T) {
|
func TestFetchPruneConfigDefault(t *testing.T) {
|
||||||
config := &Configuration{}
|
config := &Configuration{}
|
||||||
fp := config.FetchPruneConfig()
|
fp := config.FetchPruneConfig()
|
||||||
@ -416,5 +420,27 @@ func TestFetchPruneConfigCustom(t *testing.T) {
|
|||||||
assert.Equal(t, 9, fp.FetchRecentCommitsDays)
|
assert.Equal(t, 9, fp.FetchRecentCommitsDays)
|
||||||
assert.Equal(t, 30, fp.PruneOffsetDays)
|
assert.Equal(t, 30, fp.PruneOffsetDays)
|
||||||
assert.Equal(t, false, fp.FetchRecentRefsIncludeRemotes)
|
assert.Equal(t, false, fp.FetchRecentRefsIncludeRemotes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// only used for tests
|
||||||
|
func (c *Configuration) SetConfig(key, value string) {
|
||||||
|
if c.loadGitConfig() {
|
||||||
|
c.loading.Lock()
|
||||||
|
c.origConfig = make(map[string]string)
|
||||||
|
for k, v := range c.gitConfig {
|
||||||
|
c.origConfig[k] = v
|
||||||
|
}
|
||||||
|
c.loading.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
c.gitConfig[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Configuration) ResetConfig() {
|
||||||
|
c.loading.Lock()
|
||||||
|
c.gitConfig = make(map[string]string)
|
||||||
|
for k, v := range c.origConfig {
|
||||||
|
c.gitConfig[k] = v
|
||||||
|
}
|
||||||
|
c.loading.Unlock()
|
||||||
}
|
}
|
||||||
|
@ -3,69 +3,124 @@ package lfs
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type credentialFetcher interface {
|
// getCreds gets the credentials for the given request's URL, and sets its
|
||||||
Credentials() Creds
|
// Authorization header with them using Basic Authentication. This is like
|
||||||
|
// getCredsForAPI(), but skips checking the LFS url or git remote.
|
||||||
|
func getCreds(req *http.Request) (Creds, error) {
|
||||||
|
if len(req.Header.Get("Authorization")) > 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
creds, err := fillCredentials(req.URL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
setRequestAuth(req, creds["username"], creds["password"])
|
||||||
|
return creds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type credentialFunc func(Creds, string) (credentialFetcher, error)
|
// getCredsForAPI gets the credentials for LFS API requests and sets the given
|
||||||
|
// request's Authorization header with them using Basic Authentication.
|
||||||
|
// 1. Check the LFS URL for authentication. Ex: http://user:pass@example.com
|
||||||
|
// 2. Check the Git remote URL for authentication IF it's the same scheme and
|
||||||
|
// host of the LFS URL.
|
||||||
|
// 3. Ask 'git credential' to fill in the password from one of the above URLs.
|
||||||
|
//
|
||||||
|
// This prefers the Git remote URL for checking credentials so that users only
|
||||||
|
// have to enter their passwords once for Git and Git LFS. It uses the same
|
||||||
|
// URL path that Git does, in case 'useHttpPath' is enabled in the Git config.
|
||||||
|
func getCredsForAPI(req *http.Request) (Creds, error) {
|
||||||
|
if len(req.Header.Get("Authorization")) > 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
var execCreds credentialFunc
|
credsUrl, err := getCredURLForAPI(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
func credentials(u *url.URL) (Creds, error) {
|
if credsUrl == nil {
|
||||||
path := strings.TrimPrefix(u.Path, "/")
|
return nil, nil
|
||||||
creds := Creds{"protocol": u.Scheme, "host": u.Host, "path": path}
|
}
|
||||||
cmd, err := execCreds(creds, "fill")
|
|
||||||
|
creds, err := fillCredentials(credsUrl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if creds != nil {
|
||||||
|
setRequestAuth(req, creds["username"], creds["password"])
|
||||||
|
}
|
||||||
|
|
||||||
|
return creds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCredURLForAPI(req *http.Request) (*url.URL, error) {
|
||||||
|
apiUrl, err := Config.ObjectUrl("")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return cmd.Credentials(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type CredentialCmd struct {
|
// if the LFS request doesn't match the current LFS url, don't bother
|
||||||
output *bytes.Buffer
|
// attempting to set the Authorization header from the LFS or Git remote URLs.
|
||||||
SubCommand string
|
if req.URL.Scheme != apiUrl.Scheme ||
|
||||||
*exec.Cmd
|
req.URL.Host != apiUrl.Host {
|
||||||
}
|
return req.URL, nil
|
||||||
|
|
||||||
func NewCommand(input Creds, subCommand string) *CredentialCmd {
|
|
||||||
buf1 := new(bytes.Buffer)
|
|
||||||
cmd := exec.Command("git", "credential", subCommand)
|
|
||||||
|
|
||||||
cmd.Stdin = input.Buffer()
|
|
||||||
cmd.Stdout = buf1
|
|
||||||
/*
|
|
||||||
There is a reason we don't hook up stderr here:
|
|
||||||
Git's credential cache daemon helper does not close its stderr, so if this
|
|
||||||
process is the process that fires up the daemon, it will wait forever
|
|
||||||
(until the daemon exits, really) trying to read from stderr.
|
|
||||||
|
|
||||||
See https://github.com/github/git-lfs/issues/117 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
return &CredentialCmd{buf1, subCommand, cmd}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CredentialCmd) StdoutString() string {
|
|
||||||
return c.output.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CredentialCmd) Credentials() Creds {
|
|
||||||
creds := make(Creds)
|
|
||||||
|
|
||||||
for _, line := range strings.Split(c.StdoutString(), "\n") {
|
|
||||||
pieces := strings.SplitN(line, "=", 2)
|
|
||||||
if len(pieces) < 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
creds[pieces[0]] = pieces[1]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return creds
|
if setRequestAuthFromUrl(req, apiUrl) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
credsUrl := apiUrl
|
||||||
|
if len(Config.CurrentRemote) > 0 {
|
||||||
|
if u, ok := Config.GitConfig("remote." + Config.CurrentRemote + ".url"); ok {
|
||||||
|
gitRemoteUrl, err := url.Parse(u)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if gitRemoteUrl.Scheme == apiUrl.Scheme &&
|
||||||
|
gitRemoteUrl.Host == apiUrl.Host {
|
||||||
|
|
||||||
|
if setRequestAuthFromUrl(req, gitRemoteUrl) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
credsUrl = gitRemoteUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return credsUrl, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fillCredentials(u *url.URL) (Creds, error) {
|
||||||
|
path := strings.TrimPrefix(u.Path, "/")
|
||||||
|
creds := Creds{"protocol": u.Scheme, "host": u.Host, "path": path}
|
||||||
|
return execCreds(creds, "fill")
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveCredentials(creds Creds, res *http.Response) {
|
||||||
|
if creds == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch res.StatusCode {
|
||||||
|
case 401, 403:
|
||||||
|
execCreds(creds, "reject")
|
||||||
|
default:
|
||||||
|
if res.StatusCode < 300 {
|
||||||
|
execCreds(creds, "approve")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Creds map[string]string
|
type Creds map[string]string
|
||||||
@ -83,25 +138,54 @@ func (c Creds) Buffer() *bytes.Buffer {
|
|||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
type credentialFunc func(Creds, string) (Creds, error)
|
||||||
execCreds = func(input Creds, subCommand string) (credentialFetcher, error) {
|
|
||||||
cmd := NewCommand(input, subCommand)
|
func execCredsCommand(input Creds, subCommand string) (Creds, error) {
|
||||||
|
output := new(bytes.Buffer)
|
||||||
|
cmd := exec.Command("git", "credential", subCommand)
|
||||||
|
cmd.Stdin = input.Buffer()
|
||||||
|
cmd.Stdout = output
|
||||||
|
/*
|
||||||
|
There is a reason we don't hook up stderr here:
|
||||||
|
Git's credential cache daemon helper does not close its stderr, so if this
|
||||||
|
process is the process that fires up the daemon, it will wait forever
|
||||||
|
(until the daemon exits, really) trying to read from stderr.
|
||||||
|
|
||||||
|
See https://github.com/github/git-lfs/issues/117 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
err := cmd.Start()
|
err := cmd.Start()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = cmd.Wait()
|
err = cmd.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
if _, ok := err.(*exec.ExitError); ok {
|
||||||
if exitErr.ProcessState.Success() == false && !Config.GetenvBool("GIT_TERMINAL_PROMPT", true) {
|
if !Config.GetenvBool("GIT_TERMINAL_PROMPT", true) {
|
||||||
return nil, fmt.Errorf("Change the GIT_TERMINAL_PROMPT env var to be prompted to enter your credentials for %s://%s.",
|
return nil, fmt.Errorf("Change the GIT_TERMINAL_PROMPT env var to be prompted to enter your credentials for %s://%s.",
|
||||||
input["protocol"], input["host"])
|
input["protocol"], input["host"])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 'git credential' exits with 128 if the helper doesn't fill the username
|
||||||
|
// and password values.
|
||||||
|
if subCommand == "fill" && err.Error() == "exit status 128" {
|
||||||
|
return input, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cmd, fmt.Errorf("'git credential %s' error: %s\n", cmd.SubCommand, err.Error())
|
return nil, fmt.Errorf("'git credential %s' error: %s\n", subCommand, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd, nil
|
creds := make(Creds)
|
||||||
|
for _, line := range strings.Split(output.String(), "\n") {
|
||||||
|
pieces := strings.SplitN(line, "=", 2)
|
||||||
|
if len(pieces) < 2 {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
creds[pieces[0]] = pieces[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return creds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var execCreds credentialFunc = execCredsCommand
|
||||||
|
@ -2,156 +2,222 @@ package lfs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestGetCredentialsForApi(t *testing.T) {
|
||||||
|
checkGetCredentials(t, getCredsForAPI, []*getCredentialCheck{
|
||||||
|
{
|
||||||
|
Desc: "simple",
|
||||||
|
Config: map[string]string{"lfs.url": "https://git-server.com"},
|
||||||
|
Method: "GET",
|
||||||
|
Href: "https://git-server.com/foo",
|
||||||
|
Protocol: "https",
|
||||||
|
Host: "git-server.com",
|
||||||
|
Username: "git-server.com",
|
||||||
|
Password: "monkey",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Desc: "auth header",
|
||||||
|
Config: map[string]string{"lfs.url": "https://git-server.com"},
|
||||||
|
Header: map[string]string{"Authorization": "Test monkey"},
|
||||||
|
Method: "GET",
|
||||||
|
Href: "https://git-server.com/foo",
|
||||||
|
Authorization: "Test monkey",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Desc: "scheme mismatch",
|
||||||
|
Config: map[string]string{"lfs.url": "https://git-server.com"},
|
||||||
|
Method: "GET",
|
||||||
|
Href: "http://git-server.com/foo",
|
||||||
|
Protocol: "http",
|
||||||
|
Host: "git-server.com",
|
||||||
|
Path: "foo",
|
||||||
|
Username: "git-server.com",
|
||||||
|
Password: "monkey",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Desc: "host mismatch",
|
||||||
|
Config: map[string]string{"lfs.url": "https://git-server.com"},
|
||||||
|
Method: "GET",
|
||||||
|
Href: "https://git-server2.com/foo",
|
||||||
|
Protocol: "https",
|
||||||
|
Host: "git-server2.com",
|
||||||
|
Path: "foo",
|
||||||
|
Username: "git-server2.com",
|
||||||
|
Password: "monkey",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Desc: "port mismatch",
|
||||||
|
Config: map[string]string{"lfs.url": "https://git-server.com"},
|
||||||
|
Method: "GET",
|
||||||
|
Href: "https://git-server.com:8080/foo",
|
||||||
|
Protocol: "https",
|
||||||
|
Host: "git-server.com:8080",
|
||||||
|
Path: "foo",
|
||||||
|
Username: "git-server.com:8080",
|
||||||
|
Password: "monkey",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Desc: "api url auth",
|
||||||
|
Config: map[string]string{"lfs.url": "https://testuser:testpass@git-server.com"},
|
||||||
|
Method: "GET",
|
||||||
|
Href: "https://git-server.com/foo",
|
||||||
|
Authorization: "Basic " + base64.URLEncoding.EncodeToString([]byte("testuser:testpass")),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Desc: "git url auth",
|
||||||
|
CurrentRemote: "origin",
|
||||||
|
Config: map[string]string{
|
||||||
|
"lfs.url": "https://git-server.com",
|
||||||
|
"remote.origin.url": "https://gituser:gitpass@git-server.com",
|
||||||
|
},
|
||||||
|
Method: "GET",
|
||||||
|
Href: "https://git-server.com/foo",
|
||||||
|
Authorization: "Basic " + base64.URLEncoding.EncodeToString([]byte("gituser:gitpass")),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetCredentials(t *testing.T) {
|
func TestGetCredentials(t *testing.T) {
|
||||||
Config.SetConfig("lfs.url", "https://lfs-server.com")
|
checks := []*getCredentialCheck{
|
||||||
req, err := http.NewRequest("GET", "https://lfs-server.com/foo", nil)
|
{
|
||||||
|
Desc: "git server",
|
||||||
|
Method: "GET",
|
||||||
|
Href: "https://git-server.com/foo",
|
||||||
|
Protocol: "https",
|
||||||
|
Host: "git-server.com",
|
||||||
|
Username: "git-server.com",
|
||||||
|
Password: "monkey",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Desc: "separate lfs server",
|
||||||
|
Method: "GET",
|
||||||
|
Href: "https://lfs-server.com/foo",
|
||||||
|
Protocol: "https",
|
||||||
|
Host: "lfs-server.com",
|
||||||
|
Username: "lfs-server.com",
|
||||||
|
Password: "monkey",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// these properties should not change the outcome
|
||||||
|
for _, check := range checks {
|
||||||
|
check.CurrentRemote = "origin"
|
||||||
|
check.Config = map[string]string{
|
||||||
|
"lfs.url": "https://testuser:testuser@git-server.com",
|
||||||
|
"remote.origin.url": "https://gituser:gitpass@git-server.com",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkGetCredentials(t, getCreds, checks)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkGetCredentials(t *testing.T, getCredsFunc func(*http.Request) (Creds, error), checks []*getCredentialCheck) {
|
||||||
|
existingRemote := Config.CurrentRemote
|
||||||
|
for _, check := range checks {
|
||||||
|
t.Logf("Checking %q", check.Desc)
|
||||||
|
Config.CurrentRemote = check.CurrentRemote
|
||||||
|
|
||||||
|
for key, value := range check.Config {
|
||||||
|
Config.SetConfig(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(check.Method, check.Href, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Errorf("[%s] %s", check.Desc, err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
creds, err := getCreds(req)
|
for key, value := range check.Header {
|
||||||
|
req.Header.Set(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
creds, err := getCredsFunc(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Errorf("[%s] %s", check.Desc, err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if value := creds["username"]; value != "lfs-server.com" {
|
if check.ExpectCreds() {
|
||||||
t.Errorf("bad username: %s", value)
|
if creds == nil {
|
||||||
|
t.Errorf("[%s], no credentials returned", check.Desc)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if value := creds["password"]; value != "monkey" {
|
if value := creds["protocol"]; len(check.Protocol) > 0 && value != check.Protocol {
|
||||||
t.Errorf("bad password: %s", value)
|
t.Errorf("[%s] bad protocol: %q, expected: %q", check.Desc, value, check.Protocol)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "Basic " + base64.URLEncoding.EncodeToString([]byte("lfs-server.com:monkey"))
|
if value := creds["host"]; len(check.Host) > 0 && value != check.Host {
|
||||||
|
t.Errorf("[%s] bad host: %q, expected: %q", check.Desc, value, check.Host)
|
||||||
|
}
|
||||||
|
|
||||||
|
if value := creds["username"]; len(check.Username) > 0 && value != check.Username {
|
||||||
|
t.Errorf("[%s] bad username: %q, expected: %q", check.Desc, value, check.Username)
|
||||||
|
}
|
||||||
|
|
||||||
|
if value := creds["password"]; len(check.Password) > 0 && value != check.Password {
|
||||||
|
t.Errorf("[%s] bad password: %q, expected: %q", check.Desc, value, check.Password)
|
||||||
|
}
|
||||||
|
|
||||||
|
if value := creds["path"]; len(check.Path) > 0 && value != check.Path {
|
||||||
|
t.Errorf("[%s] bad path: %q, expected: %q", check.Desc, value, check.Path)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if creds != nil {
|
||||||
|
t.Errorf("[%s], unexpected credentials: %v // %v", check.Desc, creds, check)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(check.Authorization) > 0 {
|
||||||
|
if actual := req.Header.Get("Authorization"); actual != check.Authorization {
|
||||||
|
t.Errorf("[%s] Unexpected Authorization header: %s", check.Desc, actual)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rawtoken := fmt.Sprintf("%s:%s", check.Username, check.Password)
|
||||||
|
expected := "Basic " + base64.URLEncoding.EncodeToString([]byte(rawtoken))
|
||||||
if value := req.Header.Get("Authorization"); value != expected {
|
if value := req.Header.Get("Authorization"); value != expected {
|
||||||
t.Errorf("Bad Authorization. Expected '%s', got '%s'", expected, value)
|
t.Errorf("[%s] Bad Authorization. Expected '%s', got '%s'", check.Desc, expected, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Config.ResetConfig()
|
||||||
|
Config.CurrentRemote = existingRemote
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetCredentialsWithExistingAuthorization(t *testing.T) {
|
type getCredentialCheck struct {
|
||||||
Config.SetConfig("lfs.url", "https://lfs-server.com")
|
Desc string
|
||||||
req, err := http.NewRequest("GET", "http://lfs-server.com/foo", nil)
|
Config map[string]string
|
||||||
if err != nil {
|
Header map[string]string
|
||||||
t.Fatal(err)
|
Method string
|
||||||
}
|
Href string
|
||||||
|
Protocol string
|
||||||
req.Header.Set("Authorization", "Test monkey")
|
Host string
|
||||||
|
Username string
|
||||||
creds, err := getCreds(req)
|
Password string
|
||||||
if err != nil {
|
Path string
|
||||||
t.Fatal(err)
|
Authorization string
|
||||||
}
|
CurrentRemote string
|
||||||
|
|
||||||
if creds != nil {
|
|
||||||
t.Errorf("Unexpected creds: %v", creds)
|
|
||||||
}
|
|
||||||
|
|
||||||
if actual := req.Header.Get("Authorization"); actual != "Test monkey" {
|
|
||||||
t.Errorf("Unexpected Authorization header: %s", actual)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetCredentialsWithSchemeMismatch(t *testing.T) {
|
func (c *getCredentialCheck) ExpectCreds() bool {
|
||||||
Config.SetConfig("lfs.url", "https://lfs-server.com")
|
return len(c.Protocol) > 0 || len(c.Host) > 0 || len(c.Username) > 0 ||
|
||||||
req, err := http.NewRequest("GET", "http://lfs-server.com/foo", nil)
|
len(c.Password) > 0 || len(c.Path) > 0
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
creds, err := getCreds(req)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if creds != nil {
|
|
||||||
t.Errorf("Unexpected creds: %v", creds)
|
|
||||||
}
|
|
||||||
|
|
||||||
if actual := req.Header.Get("Authorization"); actual != "" {
|
|
||||||
t.Errorf("Unexpected Authorization header: %s", actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetCredentialsWithHostMismatch(t *testing.T) {
|
|
||||||
Config.SetConfig("lfs.url", "https://lfs-server.com")
|
|
||||||
req, err := http.NewRequest("GET", "https://lfs-server2.com/foo", nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
creds, err := getCreds(req)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if creds != nil {
|
|
||||||
t.Errorf("Unexpected creds: %v", creds)
|
|
||||||
}
|
|
||||||
|
|
||||||
if actual := req.Header.Get("Authorization"); actual != "" {
|
|
||||||
t.Errorf("Unexpected Authorization header: %s", actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetCredentialsWithPortMismatch(t *testing.T) {
|
|
||||||
Config.SetConfig("lfs.url", "https://lfs-server.com")
|
|
||||||
req, err := http.NewRequest("GET", "https://lfs-server:8080.com/foo", nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
creds, err := getCreds(req)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if creds != nil {
|
|
||||||
t.Errorf("Unexpected creds: %v", creds)
|
|
||||||
}
|
|
||||||
|
|
||||||
if actual := req.Header.Get("Authorization"); actual != "" {
|
|
||||||
t.Errorf("Unexpected Authorization header: %s", actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetCredentialsWithRfc1738UsernameAndPassword(t *testing.T) {
|
|
||||||
Config.SetConfig("lfs.url", "https://testuser:testpass@lfs-server.com")
|
|
||||||
req, err := http.NewRequest("GET", "https://lfs-server.com/foo", nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
creds, err := getCreds(req)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if creds != nil {
|
|
||||||
t.Errorf("unexpected creds: %v", creds)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := "Basic " + base64.URLEncoding.EncodeToString([]byte("testuser:testpass"))
|
|
||||||
if value := req.Header.Get("Authorization"); value != expected {
|
|
||||||
t.Errorf("Bad Authorization. Expected '%s', got '%s'", expected, value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
execCreds = func(input Creds, subCommand string) (credentialFetcher, error) {
|
execCreds = func(input Creds, subCommand string) (Creds, error) {
|
||||||
return &testCredentialFetcher{input}, nil
|
output := make(Creds)
|
||||||
|
for key, value := range input {
|
||||||
|
output[key] = value
|
||||||
|
}
|
||||||
|
output["username"] = input["host"]
|
||||||
|
output["password"] = "monkey"
|
||||||
|
return output, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type testCredentialFetcher struct {
|
|
||||||
Creds Creds
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *testCredentialFetcher) Credentials() Creds {
|
|
||||||
c.Creds["username"] = c.Creds["host"]
|
|
||||||
c.Creds["password"] = "monkey"
|
|
||||||
return c.Creds
|
|
||||||
}
|
|
||||||
|
@ -72,10 +72,6 @@ func TestSuccessfulDownload(t *testing.T) {
|
|||||||
t.Error("Invalid Accept")
|
t.Error("Invalid Accept")
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Header.Get("Authorization") != expectedAuth(t, server) {
|
|
||||||
t.Error("Invalid Authorization")
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.Header.Get("A") != "1" {
|
if r.Header.Get("A") != "1" {
|
||||||
t.Error("invalid A")
|
t.Error("invalid A")
|
||||||
}
|
}
|
||||||
@ -87,6 +83,7 @@ func TestSuccessfulDownload(t *testing.T) {
|
|||||||
w.Write([]byte("test"))
|
w.Write([]byte("test"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer Config.ResetConfig()
|
||||||
Config.SetConfig("lfs.url", server.URL+"/media")
|
Config.SetConfig("lfs.url", server.URL+"/media")
|
||||||
reader, size, err := Download("oid")
|
reader, size, err := Download("oid")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -204,10 +201,6 @@ func TestSuccessfulDownloadWithRedirects(t *testing.T) {
|
|||||||
t.Error("Invalid Accept")
|
t.Error("Invalid Accept")
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Header.Get("Authorization") != expectedAuth(t, server) {
|
|
||||||
t.Error("Invalid Authorization")
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.Header.Get("A") != "1" {
|
if r.Header.Get("A") != "1" {
|
||||||
t.Error("invalid A")
|
t.Error("invalid A")
|
||||||
}
|
}
|
||||||
@ -219,6 +212,7 @@ func TestSuccessfulDownloadWithRedirects(t *testing.T) {
|
|||||||
w.Write([]byte("test"))
|
w.Write([]byte("test"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer Config.ResetConfig()
|
||||||
Config.SetConfig("lfs.url", server.URL+"/redirect")
|
Config.SetConfig("lfs.url", server.URL+"/redirect")
|
||||||
|
|
||||||
for _, redirect := range redirectCodes {
|
for _, redirect := range redirectCodes {
|
||||||
@ -324,6 +318,7 @@ func TestSuccessfulDownloadWithAuthorization(t *testing.T) {
|
|||||||
w.Write([]byte("test"))
|
w.Write([]byte("test"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer Config.ResetConfig()
|
||||||
Config.SetConfig("lfs.url", server.URL+"/media")
|
Config.SetConfig("lfs.url", server.URL+"/media")
|
||||||
reader, size, err := Download("oid")
|
reader, size, err := Download("oid")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -412,10 +407,6 @@ func TestSuccessfulDownloadFromSeparateHost(t *testing.T) {
|
|||||||
t.Error("Invalid Accept")
|
t.Error("Invalid Accept")
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Header.Get("Authorization") != "" {
|
|
||||||
t.Error("Invalid Authorization")
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.Header.Get("A") != "1" {
|
if r.Header.Get("A") != "1" {
|
||||||
t.Error("invalid A")
|
t.Error("invalid A")
|
||||||
}
|
}
|
||||||
@ -427,6 +418,7 @@ func TestSuccessfulDownloadFromSeparateHost(t *testing.T) {
|
|||||||
w.Write([]byte("test"))
|
w.Write([]byte("test"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer Config.ResetConfig()
|
||||||
Config.SetConfig("lfs.url", server.URL+"/media")
|
Config.SetConfig("lfs.url", server.URL+"/media")
|
||||||
reader, size, err := Download("oid")
|
reader, size, err := Download("oid")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -546,10 +538,6 @@ func TestSuccessfulDownloadFromSeparateRedirectedHost(t *testing.T) {
|
|||||||
t.Error("Invalid Accept")
|
t.Error("Invalid Accept")
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Header.Get("Authorization") != "" {
|
|
||||||
t.Error("Invalid Authorization")
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.Header.Get("A") != "1" {
|
if r.Header.Get("A") != "1" {
|
||||||
t.Error("invalid A")
|
t.Error("invalid A")
|
||||||
}
|
}
|
||||||
@ -561,6 +549,7 @@ func TestSuccessfulDownloadFromSeparateRedirectedHost(t *testing.T) {
|
|||||||
w.Write([]byte("test"))
|
w.Write([]byte("test"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer Config.ResetConfig()
|
||||||
Config.SetConfig("lfs.url", server.URL+"/media")
|
Config.SetConfig("lfs.url", server.URL+"/media")
|
||||||
|
|
||||||
for _, redirect := range redirectCodes {
|
for _, redirect := range redirectCodes {
|
||||||
@ -597,6 +586,7 @@ func TestDownloadAPIError(t *testing.T) {
|
|||||||
w.WriteHeader(404)
|
w.WriteHeader(404)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer Config.ResetConfig()
|
||||||
Config.SetConfig("lfs.url", server.URL+"/media")
|
Config.SetConfig("lfs.url", server.URL+"/media")
|
||||||
_, _, err := Download("oid")
|
_, _, err := Download("oid")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -664,6 +654,7 @@ func TestDownloadStorageError(t *testing.T) {
|
|||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer Config.ResetConfig()
|
||||||
Config.SetConfig("lfs.url", server.URL+"/media")
|
Config.SetConfig("lfs.url", server.URL+"/media")
|
||||||
_, _, err := Download("oid")
|
_, _, err := Download("oid")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -103,6 +103,7 @@ func TestExistingUpload(t *testing.T) {
|
|||||||
w.WriteHeader(200)
|
w.WriteHeader(200)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer Config.ResetConfig()
|
||||||
Config.SetConfig("lfs.url", server.URL+"/media")
|
Config.SetConfig("lfs.url", server.URL+"/media")
|
||||||
|
|
||||||
oidPath, _ := LocalMediaPath("988881adc9fc3655077dc2d4d757d480b5ea0e11")
|
oidPath, _ := LocalMediaPath("988881adc9fc3655077dc2d4d757d480b5ea0e11")
|
||||||
@ -226,6 +227,7 @@ func TestUploadWithRedirect(t *testing.T) {
|
|||||||
w.Write(by)
|
w.Write(by)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer Config.ResetConfig()
|
||||||
Config.SetConfig("lfs.url", server.URL+"/redirect")
|
Config.SetConfig("lfs.url", server.URL+"/redirect")
|
||||||
|
|
||||||
oidPath, _ := LocalMediaPath("988881adc9fc3655077dc2d4d757d480b5ea0e11")
|
oidPath, _ := LocalMediaPath("988881adc9fc3655077dc2d4d757d480b5ea0e11")
|
||||||
@ -399,6 +401,7 @@ func TestSuccessfulUploadWithVerify(t *testing.T) {
|
|||||||
w.WriteHeader(200)
|
w.WriteHeader(200)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer Config.ResetConfig()
|
||||||
Config.SetConfig("lfs.url", server.URL+"/media")
|
Config.SetConfig("lfs.url", server.URL+"/media")
|
||||||
|
|
||||||
oidPath, _ := LocalMediaPath("988881adc9fc3655077dc2d4d757d480b5ea0e11")
|
oidPath, _ := LocalMediaPath("988881adc9fc3655077dc2d4d757d480b5ea0e11")
|
||||||
@ -559,6 +562,7 @@ func TestSuccessfulUploadWithoutVerify(t *testing.T) {
|
|||||||
w.WriteHeader(200)
|
w.WriteHeader(200)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer Config.ResetConfig()
|
||||||
Config.SetConfig("lfs.url", server.URL+"/media")
|
Config.SetConfig("lfs.url", server.URL+"/media")
|
||||||
|
|
||||||
oidPath, _ := LocalMediaPath("988881adc9fc3655077dc2d4d757d480b5ea0e11")
|
oidPath, _ := LocalMediaPath("988881adc9fc3655077dc2d4d757d480b5ea0e11")
|
||||||
@ -603,6 +607,7 @@ func TestUploadApiError(t *testing.T) {
|
|||||||
w.WriteHeader(404)
|
w.WriteHeader(404)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer Config.ResetConfig()
|
||||||
Config.SetConfig("lfs.url", server.URL+"/media")
|
Config.SetConfig("lfs.url", server.URL+"/media")
|
||||||
|
|
||||||
oidPath, _ := LocalMediaPath("988881adc9fc3655077dc2d4d757d480b5ea0e11")
|
oidPath, _ := LocalMediaPath("988881adc9fc3655077dc2d4d757d480b5ea0e11")
|
||||||
@ -710,6 +715,7 @@ func TestUploadStorageError(t *testing.T) {
|
|||||||
w.WriteHeader(404)
|
w.WriteHeader(404)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer Config.ResetConfig()
|
||||||
Config.SetConfig("lfs.url", server.URL+"/media")
|
Config.SetConfig("lfs.url", server.URL+"/media")
|
||||||
|
|
||||||
oidPath, _ := LocalMediaPath("988881adc9fc3655077dc2d4d757d480b5ea0e11")
|
oidPath, _ := LocalMediaPath("988881adc9fc3655077dc2d4d757d480b5ea0e11")
|
||||||
@ -858,6 +864,7 @@ func TestUploadVerifyError(t *testing.T) {
|
|||||||
w.WriteHeader(404)
|
w.WriteHeader(404)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer Config.ResetConfig()
|
||||||
Config.SetConfig("lfs.url", server.URL+"/media")
|
Config.SetConfig("lfs.url", server.URL+"/media")
|
||||||
|
|
||||||
oidPath, _ := LocalMediaPath("988881adc9fc3655077dc2d4d757d480b5ea0e11")
|
oidPath, _ := LocalMediaPath("988881adc9fc3655077dc2d4d757d480b5ea0e11")
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,9 +17,6 @@ var (
|
|||||||
}
|
}
|
||||||
|
|
||||||
delim = '\n'
|
delim = '\n'
|
||||||
|
|
||||||
hostRE = regexp.MustCompile(`\A127.0.0.1:\d+\z`)
|
|
||||||
|
|
||||||
credsDir = ""
|
credsDir = ""
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -74,6 +70,7 @@ func fill() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user != "skip" {
|
||||||
if _, ok := creds["username"]; !ok {
|
if _, ok := creds["username"]; !ok {
|
||||||
creds["username"] = user
|
creds["username"] = user
|
||||||
}
|
}
|
||||||
@ -81,6 +78,7 @@ func fill() {
|
|||||||
if _, ok := creds["password"]; !ok {
|
if _, ok := creds["password"]; !ok {
|
||||||
creds["password"] = pass
|
creds["password"] = pass
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for key, value := range creds {
|
for key, value := range creds {
|
||||||
fmt.Fprintf(os.Stderr, "CREDS SEND: %s=%s\n", key, value)
|
fmt.Fprintf(os.Stderr, "CREDS SEND: %s=%s\n", key, value)
|
||||||
|
@ -2,54 +2,7 @@
|
|||||||
|
|
||||||
. "test/testlib.sh"
|
. "test/testlib.sh"
|
||||||
|
|
||||||
begin_test "git credential"
|
begin_test "credentials without useHttpPath, with wrong path password"
|
||||||
(
|
|
||||||
set -e
|
|
||||||
|
|
||||||
printf "git:server" > "$CREDSDIR/credential-test.com"
|
|
||||||
printf "git:path" > "$CREDSDIR/credential-test.com--some-path"
|
|
||||||
|
|
||||||
mkdir empty
|
|
||||||
cd empty
|
|
||||||
git init
|
|
||||||
|
|
||||||
echo "protocol=http
|
|
||||||
host=credential-test.com" | GIT_TERMINAL_PROMPT=0 git credential fill | tee cred.log
|
|
||||||
|
|
||||||
expected="protocol=http
|
|
||||||
host=credential-test.com
|
|
||||||
username=git
|
|
||||||
password=server"
|
|
||||||
[ "$expected" = "$(cat cred.log)" ]
|
|
||||||
|
|
||||||
echo "protocol=http
|
|
||||||
host=credential-test.com
|
|
||||||
path=some/path" | GIT_TERMINAL_PROMPT=0 git credential fill | tee cred.log
|
|
||||||
|
|
||||||
expected="protocol=http
|
|
||||||
host=credential-test.com
|
|
||||||
username=git
|
|
||||||
password=server"
|
|
||||||
|
|
||||||
[ "$expected" = "$(cat cred.log)" ]
|
|
||||||
|
|
||||||
git config credential.useHttpPath true
|
|
||||||
|
|
||||||
echo "protocol=http
|
|
||||||
host=credential-test.com
|
|
||||||
path=some/path" | GIT_TERMINAL_PROMPT=0 git credential fill | tee cred.log
|
|
||||||
|
|
||||||
expected="protocol=http
|
|
||||||
host=credential-test.com
|
|
||||||
path=some/path
|
|
||||||
username=git
|
|
||||||
password=path"
|
|
||||||
|
|
||||||
[ "$expected" = "$(cat cred.log)" ]
|
|
||||||
)
|
|
||||||
end_test
|
|
||||||
|
|
||||||
begin_test "credentials without useHttpPath, with wrong password"
|
|
||||||
(
|
(
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
@ -136,3 +89,53 @@ begin_test "credentials with useHttpPath, with correct password"
|
|||||||
grep "(1 of 1 files)" push.log
|
grep "(1 of 1 files)" push.log
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
|
begin_test "git credential"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
printf "git:server" > "$CREDSDIR/credential-test.com"
|
||||||
|
printf "git:path" > "$CREDSDIR/credential-test.com--some-path"
|
||||||
|
|
||||||
|
mkdir empty
|
||||||
|
cd empty
|
||||||
|
git init
|
||||||
|
|
||||||
|
echo "protocol=http
|
||||||
|
host=credential-test.com" | GIT_TERMINAL_PROMPT=0 git credential fill > cred.log
|
||||||
|
cat cred.log
|
||||||
|
|
||||||
|
expected="protocol=http
|
||||||
|
host=credential-test.com
|
||||||
|
username=git
|
||||||
|
password=server"
|
||||||
|
[ "$expected" = "$(cat cred.log)" ]
|
||||||
|
|
||||||
|
echo "protocol=http
|
||||||
|
host=credential-test.com
|
||||||
|
path=some/path" | GIT_TERMINAL_PROMPT=0 git credential fill > cred.log
|
||||||
|
cat cred.log
|
||||||
|
|
||||||
|
expected="protocol=http
|
||||||
|
host=credential-test.com
|
||||||
|
username=git
|
||||||
|
password=server"
|
||||||
|
|
||||||
|
[ "$expected" = "$(cat cred.log)" ]
|
||||||
|
|
||||||
|
git config credential.useHttpPath true
|
||||||
|
|
||||||
|
echo "protocol=http
|
||||||
|
host=credential-test.com
|
||||||
|
path=some/path" | GIT_TERMINAL_PROMPT=0 git credential fill > cred.log
|
||||||
|
cat cred.log
|
||||||
|
|
||||||
|
expected="protocol=http
|
||||||
|
host=credential-test.com
|
||||||
|
path=some/path
|
||||||
|
username=git
|
||||||
|
password=path"
|
||||||
|
|
||||||
|
[ "$expected" = "$(cat cred.log)" ]
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
Loading…
Reference in New Issue
Block a user