"log"
"net/http"
"os"
- "path"
"path/filepath"
"slices"
"strings"
if err != nil {
base.Fatalf("go: could not parse netrc (GOAUTH=%s): %v", cfg.GOAUTH, err)
}
- for _, l := range lines {
+ // Process lines in reverse so that if the same machine is listed
+ // multiple times, we end up saving the earlier one
+ // (overwriting later ones). This matches the way the go command
+ // worked before GOAUTH.
+ for i := len(lines) - 1; i >= 0; i-- {
+ l := lines[i]
r := http.Request{Header: make(http.Header)}
r.SetBasicAuth(l.login, l.password)
storeCredential(l.machine, r.Header)
func loadCredential(req *http.Request, url string) bool {
currentPrefix := strings.TrimPrefix(url, "https://")
// Iteratively try prefixes, moving up the path hierarchy.
- for currentPrefix != "/" && currentPrefix != "." && currentPrefix != "" {
+ for {
headers, ok := credentialCache.Load(currentPrefix)
if !ok {
- // Move to the parent directory.
- currentPrefix = path.Dir(currentPrefix)
+ currentPrefix, _, ok = strings.Cut(currentPrefix, "/")
+ if !ok {
+ return false
+ }
continue
}
for key, values := range headers.(http.Header) {
}
return true
}
- return false
}
// storeCredential caches or removes credentials (represented by HTTP headers)
got := &http.Request{Header: make(http.Header)}
ok := loadCredential(got, tc.machine)
if !ok || !reflect.DeepEqual(got.Header, want.Header) {
- t.Errorf("loadCredential:\nhave %q\nwant %q", got.Header, want.Header)
+ t.Errorf("loadCredential(%q):\nhave %q\nwant %q", tc.machine, got.Header, want.Header)
+ }
+ }
+
+ // Having stored those credentials, we should be able to look up longer URLs too.
+ extraCases := []netrcLine{
+ {"https://api.github.com/foo", "user", "pwd"},
+ {"https://api.github.com/foo/bar/baz", "user", "pwd"},
+ {"https://example.com/abc", "", ""},
+ {"https://example.com/?/../api.github.com/", "", ""},
+ {"https://example.com/?/../api.github.com", "", ""},
+ {"https://example.com/../api.github.com/", "", ""},
+ {"https://example.com/../api.github.com", "", ""},
+ }
+ for _, tc := range extraCases {
+ want := http.Request{Header: make(http.Header)}
+ if tc.login != "" {
+ want.SetBasicAuth(tc.login, tc.password)
+ }
+ got := &http.Request{Header: make(http.Header)}
+ loadCredential(got, tc.machine)
+ if !reflect.DeepEqual(got.Header, want.Header) {
+ t.Errorf("loadCredential(%q):\nhave %q\nwant %q", tc.machine, got.Header, want.Header)
}
}
}
# credentials passed in HTTPS requests to VCS servers.
# See golang.org/issue/26232
-[short] skip
-
env GOPROXY=direct
env GOSUMDB=off
env NETRC=$WORK/missing
! go get vcs-test.golang.org/auth/or401
stderr '^\tserver response: ACCESS DENIED, buddy$'
-
-- go.mod --
module private.example.com
-- $WORK/empty --
machine vcs-test.golang.org
login aladdin
password opensesame
+# first one should override this one
+machine vcs-test.golang.org
+ login aladdin
+ password ignored