Files

104 lines
2.2 KiB
Go
Raw Permalink Normal View History

//go:build linux || freebsd
// +build linux freebsd
package auth
import (
"bufio"
"os"
"path/filepath"
"strings"
)
// NetrcEntry holds credentials for a single machine entry in .netrc.
type NetrcEntry struct {
Machine string
Login string
Password string
}
// LoadNetrc reads ~/.netrc and returns entries keyed by machine name.
func LoadNetrc() (map[string]*NetrcEntry, error) {
home, err := os.UserHomeDir()
if err != nil {
return nil, nil
}
path := filepath.Join(home, ".netrc")
file, err := os.Open(path)
if err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, err
}
defer file.Close()
entries := make(map[string]*NetrcEntry)
var current *NetrcEntry
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
// Skip comments and empty lines
if line == "" || strings.HasPrefix(line, "#") {
continue
}
fields := strings.Fields(line)
// "default" is also valid but we treat it as a machine
if len(fields) >= 2 && (fields[0] == "machine" || fields[0] == "default") {
if current != nil && current.Machine != "" {
entries[current.Machine] = current
}
name := fields[1]
if fields[0] == "default" {
name = "default"
}
current = &NetrcEntry{Machine: name}
// Rest of line may have login/password
parseNetrcLine(fields[2:], current)
} else if current != nil {
parseNetrcLine(fields, current)
}
}
if current != nil && current.Machine != "" {
entries[current.Machine] = current
}
return entries, scanner.Err()
}
func parseNetrcLine(fields []string, entry *NetrcEntry) {
for i := 0; i < len(fields); i++ {
switch fields[i] {
case "login":
if i+1 < len(fields) {
entry.Login = fields[i+1]
i++
}
case "password":
if i+1 < len(fields) {
entry.Password = fields[i+1]
i++
}
}
}
}
// LookupNetrc returns credentials from .netrc for a given hostname.
func LookupNetrc(host string) (login, password string, found bool) {
entries, err := LoadNetrc()
if err != nil || entries == nil {
return "", "", false
}
// Exact match first
if e, ok := entries[host]; ok {
return e.Login, e.Password, true
}
// Default entry
if e, ok := entries["default"]; ok {
return e.Login, e.Password, true
}
return "", "", false
}