mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-04 05:22:25 -06:00 
			
		
		
		
	* start moving to bun * changing more stuff * more * and yet more * tests passing * seems stable now * more big changes * small fix * little fixes
		
			
				
	
	
		
			110 lines
		
	
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			110 lines
		
	
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Package pgpassfile is a parser PostgreSQL .pgpass files.
 | 
						|
package pgpassfile
 | 
						|
 | 
						|
import (
 | 
						|
	"bufio"
 | 
						|
	"io"
 | 
						|
	"os"
 | 
						|
	"regexp"
 | 
						|
	"strings"
 | 
						|
)
 | 
						|
 | 
						|
// Entry represents a line in a PG passfile.
 | 
						|
type Entry struct {
 | 
						|
	Hostname string
 | 
						|
	Port     string
 | 
						|
	Database string
 | 
						|
	Username string
 | 
						|
	Password string
 | 
						|
}
 | 
						|
 | 
						|
// Passfile is the in memory data structure representing a PG passfile.
 | 
						|
type Passfile struct {
 | 
						|
	Entries []*Entry
 | 
						|
}
 | 
						|
 | 
						|
// ReadPassfile reads the file at path and parses it into a Passfile.
 | 
						|
func ReadPassfile(path string) (*Passfile, error) {
 | 
						|
	f, err := os.Open(path)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	defer f.Close()
 | 
						|
 | 
						|
	return ParsePassfile(f)
 | 
						|
}
 | 
						|
 | 
						|
// ParsePassfile reads r and parses it into a Passfile.
 | 
						|
func ParsePassfile(r io.Reader) (*Passfile, error) {
 | 
						|
	passfile := &Passfile{}
 | 
						|
 | 
						|
	scanner := bufio.NewScanner(r)
 | 
						|
	for scanner.Scan() {
 | 
						|
		entry := parseLine(scanner.Text())
 | 
						|
		if entry != nil {
 | 
						|
			passfile.Entries = append(passfile.Entries, entry)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return passfile, scanner.Err()
 | 
						|
}
 | 
						|
 | 
						|
// Match (not colons or escaped colon or escaped backslash)+. Essentially gives a split on unescaped
 | 
						|
// colon.
 | 
						|
var colonSplitterRegexp = regexp.MustCompile("(([^:]|(\\:)))+")
 | 
						|
 | 
						|
// var colonSplitterRegexp = regexp.MustCompile("((?:[^:]|(?:\\:)|(?:\\\\))+)")
 | 
						|
 | 
						|
// parseLine parses a line into an *Entry. It returns nil on comment lines or any other unparsable
 | 
						|
// line.
 | 
						|
func parseLine(line string) *Entry {
 | 
						|
	const (
 | 
						|
		tmpBackslash = "\r"
 | 
						|
		tmpColon     = "\n"
 | 
						|
	)
 | 
						|
 | 
						|
	line = strings.TrimSpace(line)
 | 
						|
 | 
						|
	if strings.HasPrefix(line, "#") {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	line = strings.Replace(line, `\\`, tmpBackslash, -1)
 | 
						|
	line = strings.Replace(line, `\:`, tmpColon, -1)
 | 
						|
 | 
						|
	parts := strings.Split(line, ":")
 | 
						|
	if len(parts) != 5 {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	// Unescape escaped colons and backslashes
 | 
						|
	for i := range parts {
 | 
						|
		parts[i] = strings.Replace(parts[i], tmpBackslash, `\`, -1)
 | 
						|
		parts[i] = strings.Replace(parts[i], tmpColon, `:`, -1)
 | 
						|
	}
 | 
						|
 | 
						|
	return &Entry{
 | 
						|
		Hostname: parts[0],
 | 
						|
		Port:     parts[1],
 | 
						|
		Database: parts[2],
 | 
						|
		Username: parts[3],
 | 
						|
		Password: parts[4],
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// FindPassword finds the password for the provided hostname, port, database, and username. For a
 | 
						|
// Unix domain socket hostname must be set to "localhost". An empty string will be returned if no
 | 
						|
// match is found.
 | 
						|
//
 | 
						|
// See https://www.postgresql.org/docs/current/libpq-pgpass.html for more password file information.
 | 
						|
func (pf *Passfile) FindPassword(hostname, port, database, username string) (password string) {
 | 
						|
	for _, e := range pf.Entries {
 | 
						|
		if (e.Hostname == "*" || e.Hostname == hostname) &&
 | 
						|
			(e.Port == "*" || e.Port == port) &&
 | 
						|
			(e.Database == "*" || e.Database == database) &&
 | 
						|
			(e.Username == "*" || e.Username == username) {
 | 
						|
			return e.Password
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return ""
 | 
						|
}
 |