Update a couple permissions things, no longer allow anonymous users.
This commit is contained in:
@@ -196,6 +196,9 @@ func (client *Client) PushConn(g *hall.Hall, id string, up conn.Up, tracks []con
|
|||||||
g.WallOps("Write to disk: " + err.Error())
|
g.WallOps("Write to disk: " + err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if down == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
client.down[up.Id()] = down
|
client.down[up.Id()] = down
|
||||||
return nil
|
return nil
|
||||||
@@ -699,7 +702,7 @@ func newDiskConn(client *Client, up conn.Up, remoteTracks []conn.UpTrack) (*disk
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(tracks) == 0 {
|
if len(tracks) == 0 {
|
||||||
return nil, errors.New("no usable tracks found")
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
down := &diskConn{
|
down := &diskConn{
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.stormux.org/storm/skald/conn"
|
||||||
|
"git.stormux.org/storm/skald/hall"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSanitise(t *testing.T) {
|
func TestSanitise(t *testing.T) {
|
||||||
@@ -195,6 +198,32 @@ func TestMixFrameReturnsNilForSilence(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNewDiskConnIgnoresConnectionWithoutRecordableTracks(t *testing.T) {
|
||||||
|
down, err := newDiskConn(&Client{}, &fakeUp{id: "up1"}, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if down != nil {
|
||||||
|
t.Fatalf("expected no disk connection for no tracks, got %#v", down)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPushConnDoesNotStoreConnectionWithoutRecordableTracks(t *testing.T) {
|
||||||
|
g := &hall.Hall{}
|
||||||
|
client := &Client{
|
||||||
|
hall: g,
|
||||||
|
recorder: &recorder{},
|
||||||
|
down: make(map[string]*diskConn),
|
||||||
|
}
|
||||||
|
err := client.PushConn(g, "up1", &fakeUp{id: "up1"}, nil, "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(client.down) != 0 {
|
||||||
|
t.Fatalf("stored %d down connections, expected 0", len(client.down))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestRecorderCreatesPlayableOgg(t *testing.T) {
|
func TestRecorderCreatesPlayableOgg(t *testing.T) {
|
||||||
if _, err := exec.LookPath("ffmpeg"); err != nil {
|
if _, err := exec.LookPath("ffmpeg"); err != nil {
|
||||||
t.Skip("ffmpeg not installed")
|
t.Skip("ffmpeg not installed")
|
||||||
@@ -275,3 +304,13 @@ func pcmFrame(sample int16) []byte {
|
|||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type fakeUp struct {
|
||||||
|
id string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *fakeUp) AddLocal(conn.Down) error { return nil }
|
||||||
|
func (u *fakeUp) DelLocal(conn.Down) bool { return true }
|
||||||
|
func (u *fakeUp) Id() string { return u.id }
|
||||||
|
func (u *fakeUp) Label() string { return "audio" }
|
||||||
|
func (u *fakeUp) User() (string, string) { return "user-id", "Username" }
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# shellcheck shell=bash disable=SC2034,SC2154
|
# shellcheck shell=bash disable=SC2034,SC2154
|
||||||
|
|
||||||
pkgname=skald-git
|
pkgname=skald-git
|
||||||
pkgver=0.0.0.r1531.g08b484f
|
pkgver=0.0.0.r1532.g3e06de7
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc='Audio-only hall-based conferencing server'
|
pkgdesc='Audio-only hall-based conferencing server'
|
||||||
arch=('x86_64' 'aarch64')
|
arch=('x86_64' 'aarch64')
|
||||||
|
|||||||
+7
-1
@@ -560,6 +560,12 @@ func AddClient(hall string, c Client, creds ClientCredentials) (*Hall, error) {
|
|||||||
c.SetUsername(username)
|
c.SetUsername(username)
|
||||||
c.SetPermissions(perms)
|
c.SetPermissions(perms)
|
||||||
|
|
||||||
|
for _, cc := range clients {
|
||||||
|
if !isSystemClient(cc) && cc.Username() == username {
|
||||||
|
return nil, UserError("username already in use")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !member("op", perms) {
|
if !member("op", perms) {
|
||||||
if g.locked != nil {
|
if g.locked != nil {
|
||||||
m := *g.locked
|
m := *g.locked
|
||||||
@@ -1005,7 +1011,7 @@ func (g *Hall) userExists(username string) bool {
|
|||||||
// usernames might lead to security vulnaribilities.
|
// usernames might lead to security vulnaribilities.
|
||||||
// For now, we just do the minimal validation that avoids path traversal.
|
// For now, we just do the minimal validation that avoids path traversal.
|
||||||
func validUsername(username string) bool {
|
func validUsername(username string) bool {
|
||||||
return username == "" || validHallName(username)
|
return username != "" && validHallName(username)
|
||||||
}
|
}
|
||||||
|
|
||||||
// called locked
|
// called locked
|
||||||
|
|||||||
@@ -238,6 +238,83 @@ func strPtr(s string) *string {
|
|||||||
return &s
|
return &s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEmptyUsernameIsRejected(t *testing.T) {
|
||||||
|
halls.halls = nil
|
||||||
|
oldDirectory := Directory
|
||||||
|
Directory = t.TempDir()
|
||||||
|
t.Cleanup(func() {
|
||||||
|
Directory = oldDirectory
|
||||||
|
halls.halls = nil
|
||||||
|
})
|
||||||
|
|
||||||
|
err := os.WriteFile(
|
||||||
|
filepath.Join(Directory, "empty-username-test.json"),
|
||||||
|
[]byte(`{
|
||||||
|
"wildcard-user": {"password": "secret", "permissions": "present"}
|
||||||
|
}`),
|
||||||
|
0600,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = AddClient("empty-username-test", &testClient{id: "user1"}, ClientCredentials{
|
||||||
|
Username: strPtr(""),
|
||||||
|
Password: "secret",
|
||||||
|
})
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("empty username unexpectedly joined")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDuplicateUsernameIsRejected(t *testing.T) {
|
||||||
|
halls.halls = nil
|
||||||
|
oldDirectory := Directory
|
||||||
|
Directory = t.TempDir()
|
||||||
|
t.Cleanup(func() {
|
||||||
|
Directory = oldDirectory
|
||||||
|
halls.halls = nil
|
||||||
|
})
|
||||||
|
|
||||||
|
err := os.WriteFile(
|
||||||
|
filepath.Join(Directory, "duplicate-username-test.json"),
|
||||||
|
[]byte(`{
|
||||||
|
"wildcard-user": {"password": "secret", "permissions": "present"}
|
||||||
|
}`),
|
||||||
|
0600,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = AddClient("duplicate-username-test", &testClient{id: "user1"}, ClientCredentials{
|
||||||
|
Username: strPtr("bob1"),
|
||||||
|
Password: "secret",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = AddClient("duplicate-username-test", &testClient{id: "user2"}, ClientCredentials{
|
||||||
|
Username: strPtr("bob1"),
|
||||||
|
Password: "secret",
|
||||||
|
})
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("duplicate username unexpectedly joined")
|
||||||
|
}
|
||||||
|
if got, want := err.Error(), "username already in use"; got != want {
|
||||||
|
t.Fatalf("duplicate username error = %q, want %q", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = AddClient("duplicate-username-test", &testClient{id: "user3"}, ClientCredentials{
|
||||||
|
Username: strPtr("bob2"),
|
||||||
|
Password: "secret",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("different username should join: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestLockedHallJoinMessage(t *testing.T) {
|
func TestLockedHallJoinMessage(t *testing.T) {
|
||||||
halls.halls = nil
|
halls.halls = nil
|
||||||
oldDirectory := Directory
|
oldDirectory := Directory
|
||||||
|
|||||||
@@ -376,7 +376,7 @@ are optional. The following fields are allowed:
|
|||||||
- `unrestricted-tokens`: if true, then ordinary users (without the "op"
|
- `unrestricted-tokens`: if true, then ordinary users (without the "op"
|
||||||
privilege) are allowed to create tokens;
|
privilege) are allowed to create tokens;
|
||||||
|
|
||||||
- `allow-anonymous`: if true, then users may connect with an empty username;
|
- `allow-anonymous`: obsolete and ignored. Empty usernames are rejected;
|
||||||
|
|
||||||
- `auto-subhalls`: if true, then subhalls of the form `hall/subhall`
|
- `auto-subhalls`: if true, then subhalls of the form `hall/subhall`
|
||||||
are automatically created when first accessed;
|
are automatically created when first accessed;
|
||||||
@@ -410,6 +410,11 @@ following strings:
|
|||||||
- `caption`: a user with the right to display captions (only);
|
- `caption`: a user with the right to display captions (only);
|
||||||
- `admin`: a user with the right to administer the hall (only).
|
- `admin`: a user with the right to administer the hall (only).
|
||||||
|
|
||||||
|
Usernames must be non-empty and unique among connected non-system clients in a
|
||||||
|
hall. If a `wildcard-user` is configured, users may choose arbitrary names
|
||||||
|
that are not listed in `users`, but two connected users may not use the same
|
||||||
|
name.
|
||||||
|
|
||||||
The value of the `codecs` field is an array of codecs allowed in the
|
The value of the `codecs` field is an array of codecs allowed in the
|
||||||
hall. Supported audio codecs include `"opus"`, `"g722"`, `"pcmu"` and
|
hall. Supported audio codecs include `"opus"`, `"g722"`, `"pcmu"` and
|
||||||
`"pcma"`. Opus is the default and is the codec used by Skald's
|
`"pcma"`. Opus is the default and is the codec used by Skald's
|
||||||
|
|||||||
Reference in New Issue
Block a user