f7b362519d
Parse the X-Forwarded-For header if it exists in the connection. This will allow bans to work if the server is sitting behind an Nginx reverse proxy (that has been configured to add the header). Also added a safe-guard to disallow bans for localhost so you cannot accidentally ban everybody from connecting if the server is behind a reverse proxy. This should resolve #49
173 lines
3.5 KiB
Go
173 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"math/big"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
var settings *Settings
|
|
var settingsMtx sync.Mutex
|
|
|
|
type Settings struct {
|
|
filename string
|
|
cmdLineKey string // stream key from the command line
|
|
MaxMessageCount int
|
|
TitleLength int // maximum length of the title that can be set with the /playing
|
|
AdminPassword string
|
|
Bans []BanInfo
|
|
StreamKey string
|
|
ListenAddress string
|
|
}
|
|
|
|
type BanInfo struct {
|
|
IP string
|
|
Names []string
|
|
When time.Time
|
|
}
|
|
|
|
func init() {
|
|
var err error
|
|
settings, err = LoadSettings("settings.json")
|
|
if err != nil {
|
|
panic("Unable to load settings: " + err.Error())
|
|
}
|
|
if len(settings.StreamKey) == 0 {
|
|
panic("Missing stream key is settings.json")
|
|
}
|
|
|
|
if settings.TitleLength <= 0 {
|
|
settings.TitleLength = 50
|
|
}
|
|
|
|
// Save admin password to file
|
|
if err = settings.Save(); err != nil {
|
|
panic("Unable to save settings: " + err.Error())
|
|
}
|
|
}
|
|
|
|
func LoadSettings(filename string) (*Settings, error) {
|
|
raw, err := ioutil.ReadFile(filename)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error reading file: %s", err)
|
|
}
|
|
|
|
var s *Settings
|
|
err = json.Unmarshal(raw, &s)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error unmarshaling: %s", err)
|
|
}
|
|
s.filename = filename
|
|
|
|
// have a default of 200
|
|
if s.MaxMessageCount == 0 {
|
|
s.MaxMessageCount = 300
|
|
} else if s.MaxMessageCount < 0 {
|
|
return s, fmt.Errorf("value for MaxMessageCount must be greater than 0, given %d", s.MaxMessageCount)
|
|
}
|
|
|
|
s.AdminPassword, err = generatePass(time.Now().Unix())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("unable to generate admin password: %s", err)
|
|
}
|
|
fmt.Printf("Settings reloaded. New admin password: %s\n", s.AdminPassword)
|
|
|
|
return s, nil
|
|
}
|
|
|
|
func generatePass(seed int64) (string, error) {
|
|
out := ""
|
|
for len(out) < 20 {
|
|
num, err := rand.Int(rand.Reader, big.NewInt(int64(15)))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
out = fmt.Sprintf("%s%X", out, num)
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func (s *Settings) Save() error {
|
|
marshaled, err := json.MarshalIndent(s, "", "\t")
|
|
if err != nil {
|
|
return fmt.Errorf("error marshaling: %s", err)
|
|
}
|
|
|
|
err = ioutil.WriteFile(s.filename, marshaled, 0777)
|
|
if err != nil {
|
|
return fmt.Errorf("error saving: %s", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *Settings) AddBan(host string, names []string) error {
|
|
if host == "127.0.0.1" {
|
|
return fmt.Errorf("Cannot add a ban for localhost.")
|
|
}
|
|
|
|
b := BanInfo{
|
|
Names: names,
|
|
IP: host,
|
|
When: time.Now(),
|
|
}
|
|
settings.Bans = append(settings.Bans, b)
|
|
|
|
fmt.Printf("[BAN] %q (%s) has been banned.\n", strings.Join(names, ", "), host)
|
|
|
|
return settings.Save()
|
|
}
|
|
|
|
func (s *Settings) RemoveBan(name string) error {
|
|
defer settingsMtx.Unlock()
|
|
settingsMtx.Lock()
|
|
|
|
name = strings.ToLower(name)
|
|
newBans := []BanInfo{}
|
|
for _, b := range s.Bans {
|
|
for _, n := range b.Names {
|
|
if n == name {
|
|
fmt.Printf("[ban] Removed ban for %s [%s]\n", b.IP, n)
|
|
} else {
|
|
newBans = append(newBans, b)
|
|
}
|
|
}
|
|
}
|
|
s.Bans = newBans
|
|
return settings.Save()
|
|
}
|
|
|
|
func (s *Settings) IsBanned(host string) (bool, []string) {
|
|
defer settingsMtx.Unlock()
|
|
settingsMtx.Lock()
|
|
|
|
for _, b := range s.Bans {
|
|
if b.IP == host {
|
|
return true, b.Names
|
|
}
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
func (s *Settings) SetTempKey(key string) {
|
|
defer settingsMtx.Unlock()
|
|
settingsMtx.Lock()
|
|
|
|
s.cmdLineKey = key
|
|
}
|
|
|
|
func (s *Settings) GetStreamKey() string {
|
|
defer settingsMtx.Unlock()
|
|
settingsMtx.Lock()
|
|
|
|
if len(s.cmdLineKey) > 0 {
|
|
return s.cmdLineKey
|
|
}
|
|
return s.StreamKey
|
|
}
|