Add ban API
parent
f46ce4b002
commit
ce6a8413b1
14
auth.go
14
auth.go
|
@ -2,6 +2,7 @@ package proxy
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -15,13 +16,24 @@ type user struct {
|
|||
timestamp time.Time
|
||||
}
|
||||
|
||||
type ban struct {
|
||||
addr string
|
||||
name string
|
||||
}
|
||||
|
||||
type authBackend interface {
|
||||
Exists(name string) bool
|
||||
Passwd(name string) (salt, verifier []byte, err error)
|
||||
SetPasswd(name string, salt, verifier []byte) error
|
||||
Timestamp(name string) (time.Time, error)
|
||||
Import(data []user)
|
||||
Import(in []user)
|
||||
Export() ([]user, error)
|
||||
|
||||
Ban(addr, name string) error
|
||||
Unban(id string) error
|
||||
Banned(addr *net.IPAddr) bool
|
||||
ImportBans(in []ban)
|
||||
ExportBans() ([]ban, error)
|
||||
}
|
||||
|
||||
func setAuthBackend(ab authBackend) error {
|
||||
|
|
|
@ -2,6 +2,8 @@ package proxy
|
|||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
@ -71,7 +73,7 @@ func (a authSQLite3) Timestamp(name string) (time.Time, error) {
|
|||
return time.Parse("2006-01-02 15:04:05", tstr)
|
||||
}
|
||||
|
||||
// Import clears the database and and refills it with the passed
|
||||
// Import deletes all users and and adds the passed
|
||||
// users.
|
||||
func (a authSQLite3) Import(in []user) {
|
||||
if err := a.init(); err != nil {
|
||||
|
@ -129,6 +131,94 @@ func (a authSQLite3) Export() ([]user, error) {
|
|||
return out, nil
|
||||
}
|
||||
|
||||
// Ban adds a ban entry for a network address and an associated name.
|
||||
func (a authSQLite3) Ban(addr, name string) error {
|
||||
if err := a.init(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer a.close()
|
||||
|
||||
if _, err := a.db.Exec(`INSERT INTO ban (addr, name) VALUES (?, ?);`, addr, name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unban deletes a ban entry. It accepts both network addresses
|
||||
// and player names.
|
||||
func (a authSQLite3) Unban(id string) error {
|
||||
if err := a.init(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer a.close()
|
||||
|
||||
if _, err := a.db.Exec(`DELETE FROM ban WHERE addr = ? OR name = ?;`, id, id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Banned reports whether a network address is banned
|
||||
func (a authSQLite3) Banned(addr *net.IPAddr) bool {
|
||||
if err := a.init(); err != nil {
|
||||
return true
|
||||
}
|
||||
defer a.close()
|
||||
|
||||
var name string
|
||||
if err := a.db.QueryRow(`SELECT name FROM ban WHERE addr = ?;`, addr.String()).Scan(&name); err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// ImportBans deletes all ban entries and adds the passed entries.
|
||||
func (a authSQLite3) ImportBans(in []ban) {
|
||||
if err := a.init(); err != nil {
|
||||
return
|
||||
}
|
||||
defer a.close()
|
||||
|
||||
a.db.Exec(`DELETE FROM ban;`)
|
||||
for _, b := range in {
|
||||
a.Ban(b.addr, b.name)
|
||||
}
|
||||
}
|
||||
|
||||
// ExportBans returns data that can be processed by ImportBans
|
||||
// or an error.
|
||||
func (a authSQLite3) ExportBans() ([]ban, error) {
|
||||
if err := a.init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer a.close()
|
||||
|
||||
rows, err := a.db.Query(`SELECT * FROM ban;`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var out []ban
|
||||
for rows.Next() {
|
||||
var b ban
|
||||
if err := rows.Scan(&b.addr, &b.name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out = append(out, b)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (a authSQLite3) updateTimestamp(name string) {
|
||||
a.db.Exec(`UPDATE user SET timestamp = datetime("now") WHERE name = ?;`, name)
|
||||
}
|
||||
|
@ -149,7 +239,10 @@ func (a *authSQLite3) init() error {
|
|||
name VARCHAR(20) PRIMARY KEY NOT NULL,
|
||||
salt BLOB NOT NULL,
|
||||
verifier BLOB NOT NULL,
|
||||
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP);`
|
||||
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP);
|
||||
CREATE TABLE IF NOT EXISTS ban (
|
||||
addr VARCHAR(39) PRIMARY KEY NOT NULL,
|
||||
name VARCHAR(20));`
|
||||
|
||||
if _, err := a.db.Exec(init); err != nil {
|
||||
return err
|
||||
|
|
|
@ -218,6 +218,12 @@ func handleClt(cc *ClientConn) {
|
|||
|
||||
cc.name = cmd.PlayerName
|
||||
|
||||
if authIface.Banned(cc.RemoteAddr().(*net.IPAddr)) {
|
||||
cc.Log("<--", "banned")
|
||||
cc.Kick("Banned by proxy.")
|
||||
break
|
||||
}
|
||||
|
||||
playersMu.Lock()
|
||||
_, ok := players[cc.Name()]
|
||||
if ok {
|
||||
|
|
|
@ -18,3 +18,16 @@ func (cc *ClientConn) Kick(reason string) {
|
|||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Ban disconnects the ClientConn and prevents the underlying
|
||||
// network address from connecting again.
|
||||
func (cc *ClientConn) Ban() error {
|
||||
cc.Kick("Banned by proxy.")
|
||||
return authIface.Ban(cc.RemoteAddr().String(), cc.name)
|
||||
}
|
||||
|
||||
// Unban removes a player from the ban list. It accepts both
|
||||
// network addresses and player names.
|
||||
func Unban(id string) error {
|
||||
return authIface.Unban(id)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue