aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimbeerserverDE <himbeerserverde@gmail.com>2021-09-13 15:54:57 +0200
committerHimbeerserverDE <himbeerserverde@gmail.com>2021-09-13 15:54:57 +0200
commit8ddb6cc9198add437426e85fc0b27a5c3eb91349 (patch)
tree0450c9236aa92bffaa17a5dd86542c0d68b4fa1d
parentc978ee8e278dacaac1664d51e7b46a0e0a433401 (diff)
Add simple file-based auth system by anon5
-rw-r--r--auth_files.go193
-rw-r--r--auth_sqlite3.go21
-rw-r--r--config.go11
-rw-r--r--log.go9
-rw-r--r--plugin.go8
-rw-r--r--proxy.go25
-rw-r--r--run.go2
7 files changed, 230 insertions, 39 deletions
diff --git a/auth_files.go b/auth_files.go
new file mode 100644
index 0000000..22b1e60
--- /dev/null
+++ b/auth_files.go
@@ -0,0 +1,193 @@
+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
+}
+
+// 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()))
+ break
+ }
+ }
+ }
+ }
+
+ 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)
+
+ t := time.Now().Local()
+ os.Chtimes(Path("auth/", name, "/timestamp"), t, t)
+}
diff --git a/auth_sqlite3.go b/auth_sqlite3.go
index 5562ca1..f1540c4 100644
--- a/auth_sqlite3.go
+++ b/auth_sqlite3.go
@@ -4,8 +4,6 @@ import (
"database/sql"
"errors"
"net"
- "os"
- "path/filepath"
"time"
_ "github.com/mattn/go-sqlite3"
@@ -73,8 +71,7 @@ func (a authSQLite3) Timestamp(name string) (time.Time, error) {
return time.Parse("2006-01-02 15:04:05", tstr)
}
-// Import deletes all users and and adds the passed
-// users.
+// Import deletes all users and adds the passed users.
func (a authSQLite3) Import(in []user) {
if err := a.init(); err != nil {
return
@@ -114,13 +111,14 @@ func (a authSQLite3) Export() ([]user, error) {
var out []user
for _, name := range names {
- var u user
- u.timestamp, err = a.Timestamp(name)
+ u := user{name: name}
+
+ u.timestamp, err = a.Timestamp(u.name)
if err != nil {
return nil, err
}
- u.salt, u.verifier, err = a.Passwd(name)
+ u.salt, u.verifier, err = a.Passwd(u.name)
if err != nil {
return nil, err
}
@@ -224,13 +222,8 @@ func (a authSQLite3) updateTimestamp(name string) {
}
func (a *authSQLite3) init() error {
- executable, err := os.Executable()
- if err != nil {
- return err
- }
-
- path := filepath.Dir(executable) + "/auth.sqlite"
- a.db, err = sql.Open("sqlite3", path)
+ var err error
+ a.db, err = sql.Open("sqlite3", Path("auth.sqlite3"))
if err != nil {
return err
}
diff --git a/config.go b/config.go
index 02263ba..5531954 100644
--- a/config.go
+++ b/config.go
@@ -4,7 +4,6 @@ import (
"encoding/json"
"log"
"os"
- "path/filepath"
"sync"
)
@@ -12,7 +11,7 @@ const (
defaultCmdPrefix = ">"
defaultSendInterval = 0.09
defaultUserLimit = 10
- defaultAuthBackend = "sqlite3"
+ defaultAuthBackend = "files"
defaultTelnetAddr = "[::1]:40010"
defaultBindAddr = ":40000"
defaultListInterval = 300
@@ -93,13 +92,7 @@ func LoadConfig() error {
config.UserGroups = make(map[string]string)
config.List.Interval = defaultListInterval
- executable, err := os.Executable()
- if err != nil {
- return err
- }
-
- path := filepath.Dir(executable) + "/config.json"
- f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0666)
+ f, err := os.OpenFile(Path("config.json"), os.O_RDWR|os.O_CREATE, 0666)
if err != nil {
config = oldConf
return err
diff --git a/log.go b/log.go
index 41d3d3e..53addd2 100644
--- a/log.go
+++ b/log.go
@@ -3,7 +3,6 @@ package proxy
import (
"log"
"os"
- "path/filepath"
)
var logWriter *LogWriter
@@ -27,13 +26,7 @@ func init() {
log.SetPrefix("[proxy] ")
log.SetFlags(log.Flags() | log.Lmsgprefix)
- executable, err := os.Executable()
- if err != nil {
- log.Fatal(err)
- }
-
- path := filepath.Dir(executable) + "/latest.log"
- f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
+ f, err := os.OpenFile(Path("latest.log"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
log.Fatal(err)
}
diff --git a/plugin.go b/plugin.go
index a847f64..15674f5 100644
--- a/plugin.go
+++ b/plugin.go
@@ -3,7 +3,6 @@ package proxy
import (
"log"
"os"
- "path/filepath"
"plugin"
"sync"
)
@@ -15,12 +14,7 @@ func loadPlugins() {
}
func openPlugins() {
- executable, err := os.Executable()
- if err != nil {
- log.Fatal(err)
- }
-
- path := filepath.Dir(executable) + "/plugins"
+ path := Path("plugins")
os.Mkdir(path, 0777)
dir, err := os.ReadDir(path)
diff --git a/proxy.go b/proxy.go
index df66f63..79e9e68 100644
--- a/proxy.go
+++ b/proxy.go
@@ -4,7 +4,14 @@ It also provides an API for plugins.
*/
package proxy
-import "regexp"
+import (
+ "log"
+ "os"
+ "path/filepath"
+ "regexp"
+ "strings"
+ "sync"
+)
const (
latestSerializeVer = 28
@@ -15,3 +22,19 @@ const (
)
var playerNameChars = regexp.MustCompile("^[a-zA-Z0-9-_]+$")
+
+var proxyDir string
+var proxyDirOnce sync.Once
+
+func Path(path ...string) string {
+ proxyDirOnce.Do(func() {
+ executable, err := os.Executable()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ proxyDir = filepath.Dir(executable)
+ })
+
+ return proxyDir + "/" + strings.Join(path, "")
+}
diff --git a/run.go b/run.go
index a3ae838..b3c496c 100644
--- a/run.go
+++ b/run.go
@@ -25,6 +25,8 @@ func Run() {
switch Conf().AuthBackend {
case "sqlite3":
setAuthBackend(authSQLite3{})
+ case "files":
+ setAuthBackend(authFiles{})
default:
log.Fatal("invalid auth backend")
}