65 lines
1.4 KiB
Go
65 lines
1.4 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
// GatedHosts is the set of hostnames that require FIDO2 authentication.
|
|
// Format matches k_phone's gated_hosts.txt: one "host" or "host:port" per line,
|
|
// lines starting with "#" and blank lines are ignored.
|
|
type GatedHosts struct {
|
|
mu sync.RWMutex
|
|
entries map[string]bool
|
|
}
|
|
|
|
// Load reads the gated hosts file. Missing file is not an error (empty list).
|
|
func (g *GatedHosts) Load(path string) error {
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
entries := make(map[string]bool)
|
|
sc := bufio.NewScanner(f)
|
|
for sc.Scan() {
|
|
line := strings.TrimSpace(sc.Text())
|
|
if line == "" || strings.HasPrefix(line, "#") {
|
|
continue
|
|
}
|
|
// Normalise: lowercase, strip any trailing port-free colon.
|
|
entries[strings.ToLower(line)] = true
|
|
}
|
|
|
|
g.mu.Lock()
|
|
g.entries = entries
|
|
g.mu.Unlock()
|
|
|
|
return sc.Err()
|
|
}
|
|
|
|
// Len returns the number of entries in the gated list.
|
|
func (g *GatedHosts) Len() int {
|
|
g.mu.RLock()
|
|
defer g.mu.RUnlock()
|
|
return len(g.entries)
|
|
}
|
|
|
|
// IsGated returns true if host:port matches a gated entry.
|
|
// An entry "example.com" matches any port; "example.com:8080" matches only port 8080.
|
|
func (g *GatedHosts) IsGated(host, port string) bool {
|
|
g.mu.RLock()
|
|
defer g.mu.RUnlock()
|
|
if len(g.entries) == 0 {
|
|
return false
|
|
}
|
|
h := strings.ToLower(host)
|
|
return g.entries[h] || (port != "" && g.entries[h+":"+port])
|
|
}
|