226 lines
4.6 KiB
Go
226 lines
4.6 KiB
Go
package proxy
|
|
|
|
import (
|
|
"net"
|
|
"os"
|
|
"time"
|
|
)
|
|
|
|
type authFiles struct{}
|
|
|
|
// Exists reports whether a user is registered.
|
|
func (a authFiles) Exists(name string) bool {
|
|
os.Mkdir(Path("auth"), 0700)
|
|
|
|
_, err := os.Stat(Path("auth/", name))
|
|
return err == nil
|
|
}
|
|
|
|
// Passwd returns the SRP salt and verifier of a user or an error.
|
|
func (a authFiles) Passwd(name string) (salt, verifier []byte, err error) {
|
|
os.Mkdir(Path("auth"), 0700)
|
|
|
|
salt, err = os.ReadFile(Path("auth/", name, "/salt"))
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
verifier, err = os.ReadFile(Path("auth/", name, "/verifier"))
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
a.updateTimestamp(name)
|
|
return
|
|
}
|
|
|
|
// SetPasswd creates a password entry if necessary
|
|
// and sets the password of a user.
|
|
func (a authFiles) SetPasswd(name string, salt, verifier []byte) error {
|
|
os.Mkdir(Path("auth"), 0700)
|
|
os.Mkdir(Path("auth/", name), 0700)
|
|
|
|
if err := os.WriteFile(Path("auth/", name, "/salt"), salt, 0600); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := os.WriteFile(Path("auth/", name, "/verifier"), verifier, 0600); err != nil {
|
|
return err
|
|
}
|
|
|
|
a.updateTimestamp(name)
|
|
return nil
|
|
}
|
|
|
|
// LastSrv returns the last server a user was on.
|
|
func (a authFiles) LastSrv(name string) (string, error) {
|
|
os.Mkdir(Path("auth"), 0700)
|
|
os.Mkdir(Path("auth/", name), 0700)
|
|
|
|
srv, err := os.ReadFile(Path("auth/", name, "/last_server"))
|
|
return string(srv), err
|
|
}
|
|
|
|
// SetLastSrv sets the last server a user was on.
|
|
func (a authFiles) SetLastSrv(name, srv string) error {
|
|
os.Mkdir(Path("auth"), 0700)
|
|
os.Mkdir(Path("auth/", name), 0700)
|
|
|
|
return os.WriteFile(Path("auth/", name, "/last_server"), []byte(srv), 0600)
|
|
}
|
|
|
|
// Timestamp returns the last time an authentication entry was accessed
|
|
// or an error.
|
|
func (a authFiles) Timestamp(name string) (time.Time, error) {
|
|
os.Mkdir(Path("auth"), 0700)
|
|
|
|
info, err := os.Stat(Path("auth/", name, "/timestamp"))
|
|
if err != nil {
|
|
return time.Time{}, err
|
|
}
|
|
|
|
return info.ModTime(), nil
|
|
}
|
|
|
|
// Import deletes all users and adds the passed users.
|
|
func (a authFiles) Import(in []user) {
|
|
os.Mkdir(Path("auth"), 0700)
|
|
|
|
for _, u := range in {
|
|
a.SetPasswd(u.name, u.salt, u.verifier)
|
|
os.Chtimes(Path("auth/", u.name, "/timestamp"), u.timestamp, u.timestamp)
|
|
}
|
|
}
|
|
|
|
// Export returns data that can be processed by Import
|
|
// or an error.
|
|
func (a authFiles) Export() ([]user, error) {
|
|
dir, err := os.ReadDir(Path("auth"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var out []user
|
|
for _, f := range dir {
|
|
u := user{name: f.Name()}
|
|
|
|
u.timestamp, err = a.Timestamp(u.name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
u.salt, u.verifier, err = a.Passwd(u.name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
out = append(out, u)
|
|
}
|
|
|
|
return out, nil
|
|
}
|
|
|
|
// Ban adds a ban entry for a network address and an associated name.
|
|
func (a authFiles) Ban(addr, name string) error {
|
|
os.Mkdir(Path("ban"), 0700)
|
|
return os.WriteFile(Path("ban/", addr), []byte(name), 0600)
|
|
}
|
|
|
|
// Unban deletes a ban entry. It accepts both network addresses
|
|
// and player names.
|
|
func (a authFiles) Unban(id string) error {
|
|
os.Mkdir(Path("ban"), 0700)
|
|
|
|
if err := os.Remove(Path("ban/", id)); err != nil {
|
|
if os.IsNotExist(err) {
|
|
dir, err := os.ReadDir(Path("ban"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, f := range dir {
|
|
name, err := os.ReadFile(Path("ban/", f.Name()))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if string(name) == id {
|
|
return os.Remove(Path("ban/", f.Name()))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Banned reports whether a network address is banned.
|
|
func (a authFiles) Banned(addr *net.UDPAddr) bool {
|
|
os.Mkdir(Path("ban"), 0700)
|
|
|
|
_, err := os.Stat(Path("ban/", addr.IP.String()))
|
|
if os.IsNotExist(err) {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// ImportBans deletes all ban entries and adds the passed entries.
|
|
func (a authFiles) ImportBans(in []ban) {
|
|
os.Mkdir(Path("ban"), 0700)
|
|
|
|
for _, b := range in {
|
|
a.Ban(b.addr, b.name)
|
|
}
|
|
}
|
|
|
|
// ExportBans returns data that can be processed by ImportBans
|
|
// or an error,
|
|
func (a authFiles) ExportBans() ([]ban, error) {
|
|
os.Mkdir(Path("ban"), 0700)
|
|
|
|
dir, err := os.ReadDir(Path("ban"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var out []ban
|
|
for _, f := range dir {
|
|
b := ban{addr: f.Name()}
|
|
|
|
name, err := os.ReadFile(Path("ban/", f.Name()))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
b.name = string(name)
|
|
out = append(out, b)
|
|
}
|
|
|
|
return out, nil
|
|
}
|
|
|
|
func (a authFiles) updateTimestamp(name string) {
|
|
os.Mkdir(Path("auth"), 0700)
|
|
|
|
path := Path("auth/", name, "/timestamp")
|
|
|
|
_, err := os.Stat(path)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0600)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
f.Close()
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
t := time.Now().Local()
|
|
os.Chtimes(path, t, t)
|
|
}
|