mirror of
https://github.com/jech/galene.git
synced 2024-11-09 18:25:58 +01:00
Move administrator password to data/config.json.
This commit is contained in:
parent
c64ec4ccd0
commit
c0b30c8557
5 changed files with 98 additions and 39 deletions
9
INSTALL
9
INSTALL
|
@ -12,15 +12,6 @@ On Windows, do
|
|||
go build -ldflags="-s -w"
|
||||
|
||||
|
||||
## Set the server administrator credentials
|
||||
|
||||
This step is optional, it is currently only relevant for access to the
|
||||
`/stats.html` and `/stats.json` locations.
|
||||
|
||||
mkdir data
|
||||
echo 'god:topsecret' > data/passwd
|
||||
|
||||
|
||||
## Set up a group
|
||||
|
||||
Set up a group called *test* by creating a file `groups/test.json`:
|
||||
|
|
15
README
15
README
|
@ -37,6 +37,21 @@ available commands; the output depends on whether you are an operator or
|
|||
not.
|
||||
|
||||
|
||||
# The global configuration file
|
||||
|
||||
The server may be configured in the JSON file `data/config.json`. This
|
||||
file may look as follows:
|
||||
|
||||
{
|
||||
"admin":[{"username":"root","password":"secret"}]
|
||||
}
|
||||
|
||||
The fields are as follows:
|
||||
|
||||
- `admin` defines the users allowed to look at the `/stats.html` file; it
|
||||
has the same syntax as user definitions in groups (see below).
|
||||
|
||||
|
||||
# Group definitions
|
||||
|
||||
Groups are defined by files in the `./groups` directory (this may be
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
)
|
||||
|
||||
func main() {
|
||||
var cpuprofile, memprofile, mutexprofile, httpAddr, dataDir string
|
||||
var cpuprofile, memprofile, mutexprofile, httpAddr string
|
||||
var udpRange string
|
||||
|
||||
flag.StringVar(&httpAddr, "http", ":8443", "web server `address`")
|
||||
|
@ -31,7 +31,7 @@ func main() {
|
|||
"redirect to canonical `host`")
|
||||
flag.BoolVar(&webserver.Insecure, "insecure", false,
|
||||
"act as an HTTP server rather than HTTPS")
|
||||
flag.StringVar(&dataDir, "data", "./data/",
|
||||
flag.StringVar(&group.DataDirectory, "data", "./data/",
|
||||
"data `directory`")
|
||||
flag.StringVar(&group.Directory, "groups", "./groups/",
|
||||
"group description `directory`")
|
||||
|
@ -112,7 +112,7 @@ func main() {
|
|||
log.Printf("File descriptor limit is %v, please increase it!", n)
|
||||
}
|
||||
|
||||
ice.ICEFilename = filepath.Join(dataDir, "ice-servers.json")
|
||||
ice.ICEFilename = filepath.Join(group.DataDirectory, "ice-servers.json")
|
||||
|
||||
// make sure the list of public groups is updated early
|
||||
go group.Update()
|
||||
|
@ -123,7 +123,7 @@ func main() {
|
|||
|
||||
serverDone := make(chan struct{})
|
||||
go func() {
|
||||
err := webserver.Serve(httpAddr, dataDir)
|
||||
err := webserver.Serve(httpAddr, group.DataDirectory)
|
||||
if err != nil {
|
||||
log.Printf("Server: %v", err)
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import (
|
|||
"github.com/pion/webrtc/v3"
|
||||
)
|
||||
|
||||
var Directory string
|
||||
var Directory, DataDirectory string
|
||||
var UseMDNS bool
|
||||
var UDPMin, UDPMax uint16
|
||||
|
||||
|
@ -802,8 +802,67 @@ func matchClient(group string, creds ClientCredentials, users []ClientPattern) (
|
|||
return false, false
|
||||
}
|
||||
|
||||
// Type Description represents a group description together with some
|
||||
// metadata about the JSON file it was deserialised from.
|
||||
// Configuration represents the contents of the data/config.json file.
|
||||
type Configuration struct {
|
||||
// The modtime and size of the file. These are used to detect
|
||||
// when a file has changed on disk.
|
||||
modTime time.Time `json:"-"`
|
||||
fileSize int64 `json:"-"`
|
||||
|
||||
Admin []ClientPattern `json:"admin"`
|
||||
}
|
||||
|
||||
var configuration struct {
|
||||
mu sync.Mutex
|
||||
configuration *Configuration
|
||||
}
|
||||
|
||||
func GetConfiguration() (*Configuration, error) {
|
||||
configuration.mu.Lock()
|
||||
defer configuration.mu.Unlock()
|
||||
|
||||
if configuration.configuration == nil {
|
||||
configuration.configuration = &Configuration{}
|
||||
}
|
||||
|
||||
filename := filepath.Join(DataDirectory, "config.json")
|
||||
fi, err := os.Stat(filename)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
if !configuration.configuration.modTime.Equal(
|
||||
time.Time{},
|
||||
) {
|
||||
configuration.configuration = &Configuration{}
|
||||
return configuration.configuration, nil
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if configuration.configuration.modTime.Equal(fi.ModTime()) &&
|
||||
configuration.configuration.fileSize == fi.Size() {
|
||||
return configuration.configuration, nil
|
||||
}
|
||||
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
d := json.NewDecoder(f)
|
||||
d.DisallowUnknownFields()
|
||||
var conf Configuration
|
||||
err = d.Decode(&conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
configuration.configuration = &conf
|
||||
return configuration.configuration, nil
|
||||
}
|
||||
|
||||
// Description represents a group description together with some metadata
|
||||
// about the JSON file it was deserialised from.
|
||||
type Description struct {
|
||||
// The file this was deserialised from. This is not necessarily
|
||||
// the name of the group, for example in case of a subgroup.
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package webserver
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
|
@ -327,26 +326,20 @@ func publicHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
func getPassword(dataDir string) (string, string, error) {
|
||||
f, err := os.Open(filepath.Join(dataDir, "passwd"))
|
||||
func adminMatch(username, password string) (bool, error) {
|
||||
conf, err := group.GetConfiguration()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
r := bufio.NewReader(f)
|
||||
|
||||
s, err := r.ReadString('\n')
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
return false, err
|
||||
}
|
||||
|
||||
l := strings.SplitN(strings.TrimSpace(s), ":", 2)
|
||||
if len(l) != 2 {
|
||||
return "", "", errors.New("couldn't parse passwords")
|
||||
for _, cred := range conf.Admin {
|
||||
if cred.Username == "" || cred.Username == username {
|
||||
if ok, _ := cred.Password.Match(password); ok {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return l[0], l[1], nil
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func failAuthentication(w http.ResponseWriter, realm string) {
|
||||
|
@ -356,15 +349,16 @@ func failAuthentication(w http.ResponseWriter, realm string) {
|
|||
}
|
||||
|
||||
func statsHandler(w http.ResponseWriter, r *http.Request, dataDir string) {
|
||||
u, p, err := getPassword(dataDir)
|
||||
if err != nil {
|
||||
log.Printf("Passwd: %v", err)
|
||||
username, password, ok := r.BasicAuth()
|
||||
if !ok {
|
||||
failAuthentication(w, "stats")
|
||||
return
|
||||
}
|
||||
|
||||
username, password, ok := r.BasicAuth()
|
||||
if !ok || username != u || password != p {
|
||||
if ok, err := adminMatch(username, password); !ok {
|
||||
if err != nil {
|
||||
log.Printf("Administrator password: %v", err)
|
||||
}
|
||||
failAuthentication(w, "stats")
|
||||
return
|
||||
}
|
||||
|
@ -377,7 +371,7 @@ func statsHandler(w http.ResponseWriter, r *http.Request, dataDir string) {
|
|||
|
||||
ss := stats.GetGroups()
|
||||
e := json.NewEncoder(w)
|
||||
err = e.Encode(ss)
|
||||
err := e.Encode(ss)
|
||||
if err != nil {
|
||||
log.Printf("stats.json: %v", err)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue