little update.
This commit is contained in:
parent
4d60e5918d
commit
260386bcac
28 changed files with 1070 additions and 50 deletions
125
libmxclient/determinant/mxpassfile/mxpassfile.go
Normal file
125
libmxclient/determinant/mxpassfile/mxpassfile.go
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
package mxpassfile
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// inspired by https://github.com/jackc/pgpassfile
|
||||
|
||||
// Entry represents a line in a MX passfile.
|
||||
type Entry struct {
|
||||
Matrixhost string
|
||||
Localpart string
|
||||
Domain string
|
||||
Token string
|
||||
}
|
||||
|
||||
// Passfile is the in memory data structure representing a MX 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()
|
||||
}
|
||||
|
||||
// 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"
|
||||
tmpPipe = "\n"
|
||||
)
|
||||
|
||||
line = strings.TrimSpace(line)
|
||||
|
||||
if strings.HasPrefix(line, "#") {
|
||||
return nil
|
||||
}
|
||||
|
||||
line = strings.ReplaceAll(line, `\\`, tmpBackslash)
|
||||
line = strings.ReplaceAll(line, `\|`, tmpPipe)
|
||||
|
||||
parts := strings.Split(line, "|")
|
||||
if len(parts) != 4 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unescape escaped colons and backslashes
|
||||
for i := range parts {
|
||||
parts[i] = strings.ReplaceAll(parts[i], tmpBackslash, `\`)
|
||||
parts[i] = strings.ReplaceAll(parts[i], tmpPipe, `|`)
|
||||
parts[i] = strings.TrimSpace(parts[i])
|
||||
}
|
||||
|
||||
return &Entry{
|
||||
Matrixhost: parts[0],
|
||||
Localpart: parts[1],
|
||||
Domain: parts[2],
|
||||
Token: parts[3],
|
||||
}
|
||||
}
|
||||
|
||||
func isWild(s string) bool {
|
||||
if s == "" || s == "*" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func superCMP(s1, s2 string) bool {
|
||||
if isWild(s1) || isWild(s2) {
|
||||
return true
|
||||
}
|
||||
//fmt.Printf("sCMP: '%s' '%s'\n", s1, s2)
|
||||
return s1 == s2
|
||||
}
|
||||
|
||||
// FindPassword finds the password for the provided synapsehost, localpart, and domain. An empty
|
||||
// string will be returned if no match is found.
|
||||
func (pf *Passfile) FindPassword(matrixhost, localpart, domain string) string {
|
||||
for _, e := range pf.Entries {
|
||||
if (e.Matrixhost == "*" || e.Matrixhost == matrixhost) &&
|
||||
(e.Localpart == "*" || e.Localpart == localpart) &&
|
||||
(e.Domain == "*" || e.Domain == domain) {
|
||||
return e.Token
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (pf *Passfile) FindPasswordFill(matrixhost, localpart, domain string) *Entry {
|
||||
for _, e := range pf.Entries {
|
||||
if superCMP(e.Matrixhost, matrixhost) &&
|
||||
superCMP(e.Localpart, localpart) &&
|
||||
superCMP(e.Domain, domain) {
|
||||
return e
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
59
libmxclient/determinant/mxpassfile/mxpassfile_test.go
Normal file
59
libmxclient/determinant/mxpassfile/mxpassfile_test.go
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
package mxpassfile
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func tokenComp(t *testing.T, expected string, value string) {
|
||||
if value != expected {
|
||||
t.Fatalf(`token was "%s", expected "%s"`, value, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func unescape(s string) string {
|
||||
s = strings.Replace(s, `\:`, `:`, -1)
|
||||
s = strings.Replace(s, `\\`, `\`, -1)
|
||||
return s
|
||||
}
|
||||
|
||||
var passfile = [][]string{
|
||||
{"test1:5432", "larrydb", "larry", "whatstheidea"},
|
||||
{"test1:5432", "moedb", "moe", "imbecile"},
|
||||
{"test1:5432", "curlydb", "curly", "nyuknyuknyuk"},
|
||||
{"test2:5432", "*", "shemp", "heymoe"},
|
||||
{"test2:5432", "*", "*", `test\\ing\|er`},
|
||||
{"localhost", "*", "*", "sesam"},
|
||||
{"test3", "", "", "swordfish"}, // user will be filled later
|
||||
}
|
||||
|
||||
func TestParsePassFile(t *testing.T) {
|
||||
buf := bytes.NewBufferString(`# A comment
|
||||
test1:5432|larrydb|larry|whatstheidea
|
||||
test1:5432|moedb|moe|imbecile
|
||||
test1:5432|curlydb|curly|nyuknyuknyuk
|
||||
test2:5432|*|shemp|heymoe
|
||||
test2:5432|*|*|test\\ing\|er
|
||||
localhost|*|*|sesam
|
||||
`)
|
||||
|
||||
passfile, err := ParsePassfile(buf)
|
||||
if err != nil {
|
||||
t.Fatalf(`ParsePassfile returned error: "%v"`, err)
|
||||
}
|
||||
|
||||
if len(passfile.Entries) != 6 {
|
||||
t.Fatalf(`passfile.Entries is "%d", expected 6`, len(passfile.Entries))
|
||||
}
|
||||
|
||||
tokenComp(t, "whatstheidea", passfile.FindPassword("test1:5432", "larrydb", "larry"))
|
||||
tokenComp(t, "imbecile", passfile.FindPassword("test1:5432", "moedb", "moe"))
|
||||
tokenComp(t, `test\ing|er`, passfile.FindPassword("test2:5432", "something", "else"))
|
||||
tokenComp(t, "sesam", passfile.FindPassword("localhost", "foo", "bare"))
|
||||
|
||||
tokenComp(t, "", passfile.FindPassword("wrong:5432", "larrydb", "larry"))
|
||||
tokenComp(t, "", passfile.FindPassword("test1:wrong", "larrydb", "larry"))
|
||||
tokenComp(t, "", passfile.FindPassword("test1:5432", "wrong", "larry"))
|
||||
tokenComp(t, "", passfile.FindPassword("test1:5432", "larrydb", "wrong"))
|
||||
}
|
||||
9
libmxclient/determinant/mxpassfile/readpassfile.go
Normal file
9
libmxclient/determinant/mxpassfile/readpassfile.go
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package mxpassfile
|
||||
|
||||
// ReadPassfile reads the file at path and parses it into a Passfile.
|
||||
func ReadPassfile(path string) (*Passfile, error) {
|
||||
return readPassfile(path)
|
||||
}
|
||||
22
libmxclient/determinant/mxpassfile/readpassfile_unix.go
Normal file
22
libmxclient/determinant/mxpassfile/readpassfile_unix.go
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package mxpassfile
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
)
|
||||
|
||||
// ReadPassfile reads the file at path and parses it into a Passfile.
|
||||
func ReadPassfile(path string) (*Passfile, error) {
|
||||
fileInfo, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
permissions := fileInfo.Mode().Perm()
|
||||
if permissions != 0o600 {
|
||||
return nil, errors.New("To wide permissions, ignore file")
|
||||
}
|
||||
return readPassfile(path)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue