mt-multiserver-proxy/auth_files.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)
}