Rename group package and defaults to halls
This commit is contained in:
+1
-1
@@ -2,6 +2,6 @@
|
||||
/skald
|
||||
/skaldctl/skaldctl
|
||||
/data
|
||||
/groups/**/*.json
|
||||
/halls/**/*.json
|
||||
/static/**/*.d.ts
|
||||
/static/third-party/tasks-vision
|
||||
|
||||
@@ -10,8 +10,8 @@ hall conferencing server. The current development repository is
|
||||
git clone https://git.stormux.org/storm/skald
|
||||
cd skald
|
||||
CGO_ENABLED=0 go build -ldflags='-s -w'
|
||||
mkdir groups
|
||||
echo '{"users": {"vimes": {"password":"sybil", "permissions":"op"}}}' > groups/night-watch.json
|
||||
mkdir halls
|
||||
echo '{"users": {"vimes": {"password":"sybil", "permissions":"op"}}}' > halls/night-watch.json
|
||||
./skald &
|
||||
```
|
||||
|
||||
|
||||
+15
-15
@@ -24,7 +24,7 @@ import (
|
||||
|
||||
gcodecs "git.stormux.org/storm/skald/codecs"
|
||||
"git.stormux.org/storm/skald/conn"
|
||||
"git.stormux.org/storm/skald/group"
|
||||
"git.stormux.org/storm/skald/hall"
|
||||
"git.stormux.org/storm/skald/rtptime"
|
||||
)
|
||||
|
||||
@@ -36,7 +36,7 @@ const (
|
||||
var Directory string
|
||||
|
||||
type Client struct {
|
||||
group *group.Group
|
||||
hall *hall.Hall
|
||||
id string
|
||||
|
||||
mu sync.Mutex
|
||||
@@ -50,12 +50,12 @@ func newId() string {
|
||||
return hex.EncodeToString(b)
|
||||
}
|
||||
|
||||
func New(g *group.Group) *Client {
|
||||
return &Client{group: g, id: newId()}
|
||||
func New(g *hall.Hall) *Client {
|
||||
return &Client{hall: g, id: newId()}
|
||||
}
|
||||
|
||||
func (client *Client) Group() *group.Group {
|
||||
return client.group
|
||||
func (client *Client) Hall() *hall.Hall {
|
||||
return client.hall
|
||||
}
|
||||
|
||||
func (client *Client) Id() string {
|
||||
@@ -86,7 +86,7 @@ func (client *Client) PushClient(group, kind, id, username string, perms []strin
|
||||
return nil
|
||||
}
|
||||
|
||||
func (client *Client) RequestConns(target group.Client, g *group.Group, id string) error {
|
||||
func (client *Client) RequestConns(target hall.Client, g *hall.Hall, id string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ func (client *Client) Close() error {
|
||||
|
||||
func (client *Client) Kick(id string, user *string, message string) error {
|
||||
err := client.Close()
|
||||
group.DelClient(client)
|
||||
hall.DelClient(client)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -116,8 +116,8 @@ func (client *Client) Joined(group, kind string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (client *Client) PushConn(g *group.Group, id string, up conn.Up, tracks []conn.UpTrack, replace string) error {
|
||||
if client.group != g {
|
||||
func (client *Client) PushConn(g *hall.Hall, id string, up conn.Up, tracks []conn.UpTrack, replace string) error {
|
||||
if client.hall != g {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ func (client *Client) PushConn(g *group.Group, id string, up conn.Up, tracks []c
|
||||
return nil
|
||||
}
|
||||
|
||||
directory := filepath.Join(Directory, client.group.Name())
|
||||
directory := filepath.Join(Directory, client.hall.Name())
|
||||
err := os.MkdirAll(directory, 0700)
|
||||
if err != nil {
|
||||
g.WallOps("Write to disk: " + err.Error())
|
||||
@@ -192,7 +192,7 @@ func (conn *diskConn) warn(message string) {
|
||||
return
|
||||
}
|
||||
log.Println(message)
|
||||
conn.client.group.WallOps(message)
|
||||
conn.client.hall.WallOps(message)
|
||||
conn.lastWarning = now
|
||||
}
|
||||
|
||||
@@ -330,7 +330,7 @@ func newDiskConn(client *Client, directory string, up conn.Up, remoteTracks []co
|
||||
if audio == nil {
|
||||
audio = remote
|
||||
} else {
|
||||
client.group.WallOps("Multiple audio tracks, recording just one")
|
||||
client.hall.WallOps("Multiple audio tracks, recording just one")
|
||||
}
|
||||
} else if strings.EqualFold(codec, "video/vp8") ||
|
||||
strings.EqualFold(codec, "video/vp9") ||
|
||||
@@ -338,10 +338,10 @@ func newDiskConn(client *Client, directory string, up conn.Up, remoteTracks []co
|
||||
if video == nil || video.Label() == "l" {
|
||||
video = remote
|
||||
} else if remote.Label() != "l" {
|
||||
client.group.WallOps("Multiple video tracks, recording just one")
|
||||
client.hall.WallOps("Multiple video tracks, recording just one")
|
||||
}
|
||||
} else {
|
||||
client.group.WallOps("Unknown codec, " + codec + ", not recording")
|
||||
client.hall.WallOps("Unknown codec, " + codec + ", not recording")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package group
|
||||
package hall
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -134,7 +134,7 @@ type ClientCredentials struct {
|
||||
}
|
||||
|
||||
type Client interface {
|
||||
Group() *Group
|
||||
Hall() *Hall
|
||||
Addr() net.Addr
|
||||
Id() string
|
||||
Username() string
|
||||
@@ -142,9 +142,9 @@ type Client interface {
|
||||
Permissions() []string
|
||||
SetPermissions([]string)
|
||||
Data() map[string]interface{}
|
||||
PushConn(g *Group, id string, conn conn.Up, tracks []conn.UpTrack, replace string) error
|
||||
RequestConns(target Client, g *Group, id string) error
|
||||
Joined(group, kind string) error
|
||||
PushClient(group, kind, id, username string, perms []string, data map[string]interface{}) error
|
||||
PushConn(g *Hall, id string, conn conn.Up, tracks []conn.UpTrack, replace string) error
|
||||
RequestConns(target Client, g *Hall, id string) error
|
||||
Joined(hall, kind string) error
|
||||
PushClient(hall, kind, id, username string, perms []string, data map[string]interface{}) error
|
||||
Kick(id string, user *string, message string) error
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package group
|
||||
package hall
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -1,4 +1,4 @@
|
||||
package group
|
||||
package hall
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -147,11 +147,11 @@ func (u UserDescription) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(uu)
|
||||
}
|
||||
|
||||
// Description represents a group description together with some metadata
|
||||
// Description represents a hall 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.
|
||||
// the name of the hall, for example in case of a subgroup.
|
||||
FileName string `json:"-"`
|
||||
|
||||
// The modtime and size of the file. These are used to detect
|
||||
@@ -162,10 +162,10 @@ type Description struct {
|
||||
// Whether this is an automatically generated subgroup
|
||||
isSubgroup bool `json:"-"`
|
||||
|
||||
// The user-friendly group name
|
||||
// The user-friendly hall name
|
||||
DisplayName string `json:"displayName,omitempty"`
|
||||
|
||||
// A user-readable description of the group.
|
||||
// A user-readable description of the hall.
|
||||
Description string `json:"description,omitempty"`
|
||||
|
||||
// A user-readable contact, typically an e-mail address.
|
||||
@@ -174,10 +174,10 @@ type Description struct {
|
||||
// A user-readable comment. Ignored by the server.
|
||||
Comment string `json:"comment,omitempty"`
|
||||
|
||||
// Whether to display the group on the landing page.
|
||||
// Whether to display the hall on the landing page.
|
||||
Public bool `json:"public,omitempty"`
|
||||
|
||||
// A URL to redirect the group to. If this is not empty, most
|
||||
// A URL to redirect the hall to. If this is not empty, most
|
||||
// other fields are ignored.
|
||||
Redirect string `json:"redirect,omitempty"`
|
||||
|
||||
@@ -202,7 +202,7 @@ type Description struct {
|
||||
// Whether subgroups are created on the fly.
|
||||
AutoSubgroups bool `json:"auto-subgroups,omitempty"`
|
||||
|
||||
// Whether to lock the group when the last op logs out.
|
||||
// Whether to lock the hall when the last op logs out.
|
||||
Autolock bool `json:"autolock,omitempty"`
|
||||
|
||||
// Whether to kick all users when the last op logs out.
|
||||
@@ -278,7 +278,7 @@ func descriptionMatch(d1, d2 *Description) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// descriptionUnchanged returns true if a group's description hasn't
|
||||
// descriptionUnchanged returns true if a hall's description hasn't
|
||||
// changed since it was last read.
|
||||
func descriptionUnchanged(name string, desc *Description) bool {
|
||||
fi, fileName, _, err := getDescriptionFile(name, true, os.Stat)
|
||||
@@ -292,7 +292,7 @@ func descriptionUnchanged(name string, desc *Description) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// GetDescription gets a group description, either from cache or from disk
|
||||
// GetDescription gets a hall description, either from cache or from disk
|
||||
func GetDescription(name string) (*Description, error) {
|
||||
g := Get(name)
|
||||
if g != nil {
|
||||
@@ -336,10 +336,10 @@ func makeETag(fileSize int64, modTime time.Time) string {
|
||||
}
|
||||
|
||||
// DeleteDescription deletes a description (and therefore persistently
|
||||
// deletes a group) but only if it matches a given ETag.
|
||||
// deletes a hall) but only if it matches a given ETag.
|
||||
func DeleteDescription(name, etag string) error {
|
||||
groups.mu.Lock()
|
||||
defer groups.mu.Unlock()
|
||||
halls.mu.Lock()
|
||||
defer halls.mu.Unlock()
|
||||
|
||||
fi, fileName, _, err := getDescriptionFile(name, false, os.Stat)
|
||||
if err != nil {
|
||||
@@ -352,14 +352,14 @@ func DeleteDescription(name, etag string) error {
|
||||
}
|
||||
|
||||
// UpdateDescription overwrites a description if it matches a given ETag.
|
||||
// In order to create a new group, pass an empty ETag.
|
||||
// In order to create a new hall, pass an empty ETag.
|
||||
func UpdateDescription(name, etag string, desc *Description) error {
|
||||
if desc.Users != nil || desc.WildcardUser != nil || desc.AuthKeys != nil {
|
||||
return errors.New("description is not sanitised")
|
||||
}
|
||||
|
||||
groups.mu.Lock()
|
||||
defer groups.mu.Unlock()
|
||||
halls.mu.Lock()
|
||||
defer halls.mu.Unlock()
|
||||
|
||||
oldetag := ""
|
||||
var filename string
|
||||
@@ -438,7 +438,7 @@ func rewriteDescriptionFile(filename string, desc *Description) error {
|
||||
|
||||
}
|
||||
|
||||
// readDescription reads a group's description from disk
|
||||
// readDescription reads a hall's description from disk
|
||||
func readDescription(name string, allowSubgroups bool) (*Description, error) {
|
||||
r, fileName, isSubgroup, err :=
|
||||
getDescriptionFile(name, allowSubgroups, os.Open)
|
||||
@@ -585,7 +585,7 @@ func GetDescriptionNames() ([]string, error) {
|
||||
return names, err
|
||||
}
|
||||
|
||||
func SetKeys(group string, keys []map[string]any) error {
|
||||
func SetKeys(hall string, keys []map[string]any) error {
|
||||
if keys != nil {
|
||||
_, err := token.ParseKeys(keys, "", "")
|
||||
if err != nil {
|
||||
@@ -593,10 +593,10 @@ func SetKeys(group string, keys []map[string]any) error {
|
||||
}
|
||||
}
|
||||
|
||||
groups.mu.Lock()
|
||||
defer groups.mu.Unlock()
|
||||
halls.mu.Lock()
|
||||
defer halls.mu.Unlock()
|
||||
|
||||
desc, err := readDescription(group, false)
|
||||
desc, err := readDescription(hall, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -604,8 +604,8 @@ func SetKeys(group string, keys []map[string]any) error {
|
||||
return rewriteDescriptionFile(desc.FileName, desc)
|
||||
}
|
||||
|
||||
func GetUsers(group string) ([]string, string, error) {
|
||||
desc, err := GetDescription(group)
|
||||
func GetUsers(hall string) ([]string, string, error) {
|
||||
desc, err := GetDescription(hall)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -618,13 +618,13 @@ func GetUsers(group string) ([]string, string, error) {
|
||||
return users, makeETag(desc.fileSize, desc.modTime), nil
|
||||
}
|
||||
|
||||
func GetSanitisedUser(group, username string, wildcard bool) (UserDescription, string, error) {
|
||||
func GetSanitisedUser(hall, username string, wildcard bool) (UserDescription, string, error) {
|
||||
if wildcard && username != "" {
|
||||
return UserDescription{}, "",
|
||||
errors.New("wildcard with username")
|
||||
}
|
||||
|
||||
desc, err := GetDescription(group)
|
||||
desc, err := GetDescription(hall)
|
||||
if err != nil {
|
||||
return UserDescription{}, "", err
|
||||
}
|
||||
@@ -651,20 +651,20 @@ func GetSanitisedUser(group, username string, wildcard bool) (UserDescription, s
|
||||
return u, makeETag(desc.fileSize, desc.modTime), nil
|
||||
}
|
||||
|
||||
func GetUserTag(group, username string, wildcard bool) (string, error) {
|
||||
_, etag, err := GetSanitisedUser(group, username, wildcard)
|
||||
func GetUserTag(hall, username string, wildcard bool) (string, error) {
|
||||
_, etag, err := GetSanitisedUser(hall, username, wildcard)
|
||||
return etag, err
|
||||
}
|
||||
|
||||
func DeleteUser(group, username string, wildcard bool, etag string) error {
|
||||
func DeleteUser(hall, username string, wildcard bool, etag string) error {
|
||||
if wildcard && username != "" {
|
||||
return errors.New("wildcard with username")
|
||||
}
|
||||
|
||||
groups.mu.Lock()
|
||||
defer groups.mu.Unlock()
|
||||
halls.mu.Lock()
|
||||
defer halls.mu.Unlock()
|
||||
|
||||
desc, err := readDescription(group, false)
|
||||
desc, err := readDescription(hall, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -697,7 +697,7 @@ func DeleteUser(group, username string, wildcard bool, etag string) error {
|
||||
return rewriteDescriptionFile(desc.FileName, desc)
|
||||
}
|
||||
|
||||
func UpdateUser(group, username string, wildcard bool, etag string, user *UserDescription) error {
|
||||
func UpdateUser(hall, username string, wildcard bool, etag string, user *UserDescription) error {
|
||||
if wildcard && username != "" {
|
||||
return errors.New("wildcard with username")
|
||||
}
|
||||
@@ -705,10 +705,10 @@ func UpdateUser(group, username string, wildcard bool, etag string, user *UserDe
|
||||
return errors.New("user description is not sanitised")
|
||||
}
|
||||
|
||||
groups.mu.Lock()
|
||||
defer groups.mu.Unlock()
|
||||
halls.mu.Lock()
|
||||
defer halls.mu.Unlock()
|
||||
|
||||
desc, err := readDescription(group, false)
|
||||
desc, err := readDescription(hall, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -749,15 +749,15 @@ func UpdateUser(group, username string, wildcard bool, etag string, user *UserDe
|
||||
return rewriteDescriptionFile(desc.FileName, desc)
|
||||
}
|
||||
|
||||
func SetUserPassword(group, username string, wildcard bool, pw Password) error {
|
||||
func SetUserPassword(hall, username string, wildcard bool, pw Password) error {
|
||||
if wildcard && username != "" {
|
||||
return errors.New("wildcard with username")
|
||||
}
|
||||
|
||||
groups.mu.Lock()
|
||||
defer groups.mu.Unlock()
|
||||
halls.mu.Lock()
|
||||
defer halls.mu.Unlock()
|
||||
|
||||
desc, err := readDescription(group, false)
|
||||
desc, err := readDescription(hall, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package group
|
||||
package hall
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -1,4 +1,4 @@
|
||||
package group
|
||||
package hall
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -98,7 +98,7 @@ const (
|
||||
MaxBitrate = 1024 * 1024 * 1024
|
||||
)
|
||||
|
||||
type Group struct {
|
||||
type Hall struct {
|
||||
name string
|
||||
|
||||
mu sync.Mutex
|
||||
@@ -110,11 +110,11 @@ type Group struct {
|
||||
data map[string]interface{}
|
||||
}
|
||||
|
||||
func (g *Group) Name() string {
|
||||
func (g *Hall) Name() string {
|
||||
return g.name
|
||||
}
|
||||
|
||||
func (g *Group) Locked() (bool, string) {
|
||||
func (g *Hall) Locked() (bool, string) {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
if g.locked != nil {
|
||||
@@ -124,7 +124,7 @@ func (g *Group) Locked() (bool, string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Group) SetLocked(locked bool, message string) {
|
||||
func (g *Hall) SetLocked(locked bool, message string) {
|
||||
g.mu.Lock()
|
||||
if locked {
|
||||
g.locked = &message
|
||||
@@ -139,13 +139,13 @@ func (g *Group) SetLocked(locked bool, message string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Group) Data() map[string]interface{} {
|
||||
func (g *Hall) Data() map[string]interface{} {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
return maps.Clone(g.data)
|
||||
}
|
||||
|
||||
func (g *Group) UpdateData(d map[string]interface{}) {
|
||||
func (g *Hall) UpdateData(d map[string]interface{}) {
|
||||
g.mu.Lock()
|
||||
if g.data == nil {
|
||||
g.data = make(map[string]interface{})
|
||||
@@ -165,19 +165,19 @@ func (g *Group) UpdateData(d map[string]interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Group) Description() *Description {
|
||||
func (g *Hall) Description() *Description {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
return g.description
|
||||
}
|
||||
|
||||
func (g *Group) ClientCount() int {
|
||||
func (g *Hall) ClientCount() int {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
return len(g.clients)
|
||||
}
|
||||
|
||||
func (g *Group) mayExpire() bool {
|
||||
func (g *Hall) mayExpire() bool {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
|
||||
@@ -190,12 +190,12 @@ func (g *Group) mayExpire() bool {
|
||||
return time.Since(g.timestamp) > maxHistoryAge(g.description)
|
||||
}
|
||||
|
||||
var groups struct {
|
||||
var halls struct {
|
||||
mu sync.Mutex
|
||||
groups map[string]*Group
|
||||
halls map[string]*Hall
|
||||
}
|
||||
|
||||
func (g *Group) API() (*webrtc.API, error) {
|
||||
func (g *Hall) API() (*webrtc.API, error) {
|
||||
g.mu.Lock()
|
||||
codecs := g.description.Codecs
|
||||
g.mu.Unlock()
|
||||
@@ -432,7 +432,7 @@ func APIFromNames(names []string) (*webrtc.API, error) {
|
||||
return APIFromCodecs(codecs)
|
||||
}
|
||||
|
||||
func Add(name string, desc *Description) (*Group, error) {
|
||||
func Add(name string, desc *Description) (*Hall, error) {
|
||||
g, notify, err := add(name, desc)
|
||||
for _, c := range notify {
|
||||
c.Joined(g.Name(), "change")
|
||||
@@ -440,7 +440,7 @@ func Add(name string, desc *Description) (*Group, error) {
|
||||
return g, err
|
||||
}
|
||||
|
||||
func validGroupName(name string) bool {
|
||||
func validHallName(name string) bool {
|
||||
if strings.ContainsRune(name, '\\') {
|
||||
return false
|
||||
}
|
||||
@@ -458,21 +458,21 @@ func validGroupName(name string) bool {
|
||||
return s == "/"+name
|
||||
}
|
||||
|
||||
func add(name string, desc *Description) (*Group, []Client, error) {
|
||||
if !validGroupName(name) {
|
||||
return nil, nil, UserError("illegal group name")
|
||||
func add(name string, desc *Description) (*Hall, []Client, error) {
|
||||
if !validHallName(name) {
|
||||
return nil, nil, UserError("illegal hall name")
|
||||
}
|
||||
|
||||
groups.mu.Lock()
|
||||
defer groups.mu.Unlock()
|
||||
halls.mu.Lock()
|
||||
defer halls.mu.Unlock()
|
||||
|
||||
if groups.groups == nil {
|
||||
groups.groups = make(map[string]*Group)
|
||||
if halls.halls == nil {
|
||||
halls.halls = make(map[string]*Hall)
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
g := groups.groups[name]
|
||||
g := halls.halls[name]
|
||||
if g == nil {
|
||||
if desc == nil {
|
||||
desc, err = readDescription(name, true)
|
||||
@@ -481,13 +481,13 @@ func add(name string, desc *Description) (*Group, []Client, error) {
|
||||
}
|
||||
}
|
||||
|
||||
g = &Group{
|
||||
g = &Hall{
|
||||
name: name,
|
||||
description: desc,
|
||||
clients: make(map[string]Client),
|
||||
timestamp: time.Now(),
|
||||
}
|
||||
groups.groups[name] = g
|
||||
halls.halls[name] = g
|
||||
}
|
||||
|
||||
g.mu.Lock()
|
||||
@@ -503,7 +503,7 @@ func add(name string, desc *Description) (*Group, []Client, error) {
|
||||
desc, err = readDescription(name, true)
|
||||
if err != nil {
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
log.Printf("Reading group %v: %v", name, err)
|
||||
log.Printf("Reading hall %v: %v", name, err)
|
||||
}
|
||||
deleteUnlocked(g)
|
||||
return nil, nil, err
|
||||
@@ -521,11 +521,11 @@ func add(name string, desc *Description) (*Group, []Client, error) {
|
||||
return g, clients, nil
|
||||
}
|
||||
|
||||
func Range(f func(g *Group) bool) {
|
||||
groups.mu.Lock()
|
||||
defer groups.mu.Unlock()
|
||||
func Range(f func(g *Hall) bool) {
|
||||
halls.mu.Lock()
|
||||
defer halls.mu.Unlock()
|
||||
|
||||
for _, g := range groups.groups {
|
||||
for _, g := range halls.halls {
|
||||
ok := f(g)
|
||||
if !ok {
|
||||
break
|
||||
@@ -536,7 +536,7 @@ func Range(f func(g *Group) bool) {
|
||||
func GetNames() []string {
|
||||
names := make([]string, 0)
|
||||
|
||||
Range(func(g *Group) bool {
|
||||
Range(func(g *Hall) bool {
|
||||
names = append(names, g.name)
|
||||
return true
|
||||
})
|
||||
@@ -552,7 +552,7 @@ func GetSubGroups(parent string) []SubGroup {
|
||||
prefix := parent + "/"
|
||||
subgroups := make([]SubGroup, 0)
|
||||
|
||||
Range(func(g *Group) bool {
|
||||
Range(func(g *Hall) bool {
|
||||
if strings.HasPrefix(g.name, prefix) {
|
||||
g.mu.Lock()
|
||||
count := len(g.clients)
|
||||
@@ -567,19 +567,19 @@ func GetSubGroups(parent string) []SubGroup {
|
||||
return subgroups
|
||||
}
|
||||
|
||||
func Get(name string) *Group {
|
||||
groups.mu.Lock()
|
||||
defer groups.mu.Unlock()
|
||||
if groups.groups == nil {
|
||||
func Get(name string) *Hall {
|
||||
halls.mu.Lock()
|
||||
defer halls.mu.Unlock()
|
||||
if halls.halls == nil {
|
||||
return nil
|
||||
}
|
||||
return groups.groups[name]
|
||||
return halls.halls[name]
|
||||
}
|
||||
|
||||
func Delete(name string) bool {
|
||||
groups.mu.Lock()
|
||||
defer groups.mu.Unlock()
|
||||
g := groups.groups[name]
|
||||
halls.mu.Lock()
|
||||
defer halls.mu.Unlock()
|
||||
g := halls.halls[name]
|
||||
if g == nil {
|
||||
return false
|
||||
}
|
||||
@@ -589,13 +589,13 @@ func Delete(name string) bool {
|
||||
return deleteUnlocked(g)
|
||||
}
|
||||
|
||||
// Called with both groups.mu and g.mu taken.
|
||||
func deleteUnlocked(g *Group) bool {
|
||||
// Called with both halls.mu and g.mu taken.
|
||||
func deleteUnlocked(g *Hall) bool {
|
||||
if len(g.clients) != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
delete(groups.groups, g.name)
|
||||
delete(halls.halls, g.name)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -608,8 +608,8 @@ func member(v string, l []string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func AddClient(group string, c Client, creds ClientCredentials) (*Group, error) {
|
||||
g, err := Add(group, nil)
|
||||
func AddClient(hall string, c Client, creds ClientCredentials) (*Hall, error) {
|
||||
g, err := Add(hall, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -632,7 +632,7 @@ func AddClient(group string, c Client, creds ClientCredentials) (*Group, error)
|
||||
if g.locked != nil {
|
||||
m := *g.locked
|
||||
if m == "" {
|
||||
m = "this group is locked"
|
||||
m = "this hall is locked"
|
||||
}
|
||||
return nil, UserError(m)
|
||||
}
|
||||
@@ -642,13 +642,13 @@ func AddClient(group string, c Client, creds ClientCredentials) (*Group, error)
|
||||
if g.description.NotBefore != nil &&
|
||||
g.description.NotBefore.After(now) {
|
||||
return nil, UserError(
|
||||
"this group is not open yet",
|
||||
"this hall is not open yet",
|
||||
)
|
||||
}
|
||||
if g.description.Expires != nil &&
|
||||
g.description.Expires.Before(now) {
|
||||
return nil, UserError(
|
||||
"this group is closed",
|
||||
"this hall is closed",
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -663,7 +663,7 @@ func AddClient(group string, c Client, creds ClientCredentials) (*Group, error)
|
||||
if !ops {
|
||||
return nil, UserError(
|
||||
"there are no operators " +
|
||||
"in this group",
|
||||
"in this hall",
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -702,7 +702,7 @@ func AddClient(group string, c Client, creds ClientCredentials) (*Group, error)
|
||||
}
|
||||
|
||||
// called locked
|
||||
func autoLockKick(g *Group) {
|
||||
func autoLockKick(g *Hall) {
|
||||
if !(g.description.Autolock && g.locked == nil) &&
|
||||
!g.description.Autokick {
|
||||
return
|
||||
@@ -715,7 +715,7 @@ func autoLockKick(g *Group) {
|
||||
}
|
||||
}
|
||||
if g.description.Autolock && g.locked == nil {
|
||||
m := "this group is locked"
|
||||
m := "this hall is locked"
|
||||
g.locked = &m
|
||||
for _, c := range clients {
|
||||
c.Joined(g.Name(), "change")
|
||||
@@ -723,14 +723,14 @@ func autoLockKick(g *Group) {
|
||||
}
|
||||
|
||||
if g.description.Autokick {
|
||||
// we cannot call kickall, since it requires the group to
|
||||
// we cannot call kickall, since it requires the hall to
|
||||
// be unlocked. And calling it asynchronously might
|
||||
// spuriously kick out an operator.
|
||||
go func(clients []Client) {
|
||||
for _, c := range clients {
|
||||
c.Kick(
|
||||
"", nil,
|
||||
"there are no operators in this group",
|
||||
"there are no operators in this hall",
|
||||
)
|
||||
}
|
||||
}(g.getClientsUnlocked(nil))
|
||||
@@ -738,7 +738,7 @@ func autoLockKick(g *Group) {
|
||||
}
|
||||
|
||||
func DelClient(c Client) {
|
||||
g := c.Group()
|
||||
g := c.Hall()
|
||||
if g == nil {
|
||||
return
|
||||
}
|
||||
@@ -762,13 +762,13 @@ func DelClient(c Client) {
|
||||
autoLockKick(g)
|
||||
}
|
||||
|
||||
func (g *Group) GetClients(except Client) []Client {
|
||||
func (g *Hall) GetClients(except Client) []Client {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
return g.getClientsUnlocked(except)
|
||||
}
|
||||
|
||||
func (g *Group) getClientsUnlocked(except Client) []Client {
|
||||
func (g *Hall) getClientsUnlocked(except Client) []Client {
|
||||
clients := make([]Client, 0, len(g.clients))
|
||||
for _, c := range g.clients {
|
||||
if c != except {
|
||||
@@ -778,13 +778,13 @@ func (g *Group) getClientsUnlocked(except Client) []Client {
|
||||
return clients
|
||||
}
|
||||
|
||||
func (g *Group) GetClient(id string) Client {
|
||||
func (g *Hall) GetClient(id string) Client {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
return g.getClientUnlocked(id)
|
||||
}
|
||||
|
||||
func (g *Group) getClientUnlocked(id string) Client {
|
||||
func (g *Hall) getClientUnlocked(id string) Client {
|
||||
for idd, c := range g.clients {
|
||||
if idd == id {
|
||||
return c
|
||||
@@ -793,7 +793,7 @@ func (g *Group) getClientUnlocked(id string) Client {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Group) Range(f func(c Client) bool) {
|
||||
func (g *Hall) Range(f func(c Client) bool) {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
for _, c := range g.clients {
|
||||
@@ -804,7 +804,7 @@ func (g *Group) Range(f func(c Client) bool) {
|
||||
}
|
||||
}
|
||||
|
||||
func kickall(g *Group, message string) {
|
||||
func kickall(g *Hall, message string) {
|
||||
g.Range(func(c Client) bool {
|
||||
c.Kick("", nil, message)
|
||||
return true
|
||||
@@ -812,7 +812,7 @@ func kickall(g *Group, message string) {
|
||||
}
|
||||
|
||||
func Shutdown(message string) {
|
||||
Range(func(g *Group) bool {
|
||||
Range(func(g *Hall) bool {
|
||||
g.SetLocked(true, message)
|
||||
kickall(g, message)
|
||||
return true
|
||||
@@ -823,7 +823,7 @@ type warner interface {
|
||||
Warn(oponly bool, message string) error
|
||||
}
|
||||
|
||||
func (g *Group) WallOps(message string) {
|
||||
func (g *Hall) WallOps(message string) {
|
||||
clients := g.GetClients(nil)
|
||||
for _, c := range clients {
|
||||
w, ok := c.(warner)
|
||||
@@ -865,7 +865,7 @@ func deleteFunc[S ~[]E, E any](s S, f func(E) bool) S {
|
||||
return s[:i]
|
||||
}
|
||||
|
||||
func (g *Group) ClearChatHistory(id string, userId string) {
|
||||
func (g *Hall) ClearChatHistory(id string, userId string) {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
if id == "" && userId == "" {
|
||||
@@ -877,7 +877,7 @@ func (g *Group) ClearChatHistory(id string, userId string) {
|
||||
})
|
||||
}
|
||||
|
||||
func (g *Group) AddToChatHistory(id, source string, user *string, time time.Time, kind string, value interface{}) {
|
||||
func (g *Hall) AddToChatHistory(id, source string, user *string, time time.Time, kind string, value interface{}) {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
|
||||
@@ -905,7 +905,7 @@ func discardObsoleteHistory(h []ChatHistoryEntry, duration time.Duration) []Chat
|
||||
return h
|
||||
}
|
||||
|
||||
func (g *Group) GetChatHistory() []ChatHistoryEntry {
|
||||
func (g *Hall) GetChatHistory() []ChatHistoryEntry {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
|
||||
@@ -993,7 +993,7 @@ func GetConfiguration() (*Configuration, error) {
|
||||
}
|
||||
|
||||
// called locked
|
||||
func (g *Group) getPasswordPermission(creds ClientCredentials) (Permissions, error) {
|
||||
func (g *Hall) getPasswordPermission(creds ClientCredentials) (Permissions, error) {
|
||||
desc := g.description
|
||||
|
||||
if creds.Username == nil {
|
||||
@@ -1024,14 +1024,14 @@ func (g *Group) getPasswordPermission(creds ClientCredentials) (Permissions, err
|
||||
|
||||
// Return true if there is a user entry with the given username.
|
||||
// Always return false for an empty username.
|
||||
func (g *Group) UserExists(username string) bool {
|
||||
func (g *Hall) UserExists(username string) bool {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
return g.userExists(username)
|
||||
}
|
||||
|
||||
// called locked
|
||||
func (g *Group) userExists(username string) bool {
|
||||
func (g *Hall) userExists(username string) bool {
|
||||
desc := g.description
|
||||
if desc.Users == nil {
|
||||
return false
|
||||
@@ -1046,11 +1046,11 @@ func (g *Group) userExists(username string) bool {
|
||||
// usernames might lead to security vulnaribilities.
|
||||
// For now, we just do the minimal validation that avoids path traversal.
|
||||
func validUsername(username string) bool {
|
||||
return username == "" || validGroupName(username)
|
||||
return username == "" || validHallName(username)
|
||||
}
|
||||
|
||||
// called locked
|
||||
func (g *Group) getPermission(creds ClientCredentials) (string, []string, error) {
|
||||
func (g *Hall) getPermission(creds ClientCredentials) (string, []string, error) {
|
||||
desc := g.description
|
||||
var username string
|
||||
var perms []string
|
||||
@@ -1096,7 +1096,7 @@ func (g *Group) getPermission(creds ClientCredentials) (string, []string, error)
|
||||
return username, perms, nil
|
||||
}
|
||||
|
||||
func (g *Group) GetPermission(creds ClientCredentials) (string, []string, error) {
|
||||
func (g *Hall) GetPermission(creds ClientCredentials) (string, []string, error) {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
return g.getPermission(creds)
|
||||
@@ -1116,10 +1116,10 @@ type Status struct {
|
||||
CanChangePassword bool `json:"canChangePassword,omitempty"`
|
||||
}
|
||||
|
||||
// Status returns a group's status.
|
||||
// Base is the base URL for groups; if omitted, then both the Location and
|
||||
// Status returns a hall's status.
|
||||
// Base is the base URL for halls; if omitted, then both the Location and
|
||||
// Endpoint members are omitted from the result.
|
||||
func (g *Group) Status(authentified bool, base *url.URL) Status {
|
||||
func (g *Hall) Status(authentified bool, base *url.URL) Status {
|
||||
desc := g.Description()
|
||||
|
||||
if desc.Redirect != "" {
|
||||
@@ -1141,7 +1141,7 @@ func (g *Group) Status(authentified bool, base *url.URL) Status {
|
||||
Scheme: base.Scheme,
|
||||
Host: base.Host,
|
||||
Path: path.Join(
|
||||
path.Join(base.Path, "/group/"),
|
||||
path.Join(base.Path, "/hall/"),
|
||||
g.Name()) + "/",
|
||||
}
|
||||
location = l.String()
|
||||
@@ -1181,7 +1181,7 @@ func (g *Group) Status(authentified bool, base *url.URL) Status {
|
||||
|
||||
func GetPublic(base *url.URL) []Status {
|
||||
gs := make([]Status, 0)
|
||||
Range(func(g *Group) bool {
|
||||
Range(func(g *Hall) bool {
|
||||
if g.Description().Public {
|
||||
gs = append(gs, g.Status(false, base))
|
||||
}
|
||||
@@ -1193,9 +1193,9 @@ func GetPublic(base *url.URL) []Status {
|
||||
return gs
|
||||
}
|
||||
|
||||
// Update checks that all in-memory groups are up-to-date and updates the
|
||||
// list of public groups. It also removes from memory any non-public
|
||||
// groups that haven't been accessed in maxHistoryAge.
|
||||
// Update checks that all in-memory halls are up-to-date and updates the
|
||||
// list of public halls. It also removes from memory any non-public
|
||||
// halls that haven't been accessed in maxHistoryAge.
|
||||
func Update() {
|
||||
_, err := GetConfiguration()
|
||||
if err != nil {
|
||||
@@ -1214,11 +1214,11 @@ func Update() {
|
||||
|
||||
deleted := false
|
||||
if g.mayExpire() {
|
||||
// Delete checks if the group is still empty
|
||||
// Delete checks if the hall is still empty
|
||||
deleted = Delete(name)
|
||||
}
|
||||
|
||||
// update group description
|
||||
// update hall description
|
||||
if !deleted {
|
||||
Add(name, nil)
|
||||
}
|
||||
@@ -1228,14 +1228,14 @@ func Update() {
|
||||
Directory,
|
||||
func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
log.Printf("Group file %v: %v", path, err)
|
||||
log.Printf("Hall file %v: %v", path, err)
|
||||
return nil
|
||||
}
|
||||
if d.IsDir() {
|
||||
base := filepath.Base(path)
|
||||
if base[0] == '.' {
|
||||
log.Printf(
|
||||
"Ignoring group directory %v",
|
||||
"Ignoring hall directory %v",
|
||||
path,
|
||||
)
|
||||
return fs.SkipDir
|
||||
@@ -1244,25 +1244,25 @@ func Update() {
|
||||
}
|
||||
filename, err := filepath.Rel(Directory, path)
|
||||
if err != nil {
|
||||
log.Printf("Group file %v: %v", path, err)
|
||||
log.Printf("Hall file %v: %v", path, err)
|
||||
return nil
|
||||
}
|
||||
if !strings.HasSuffix(filename, ".json") {
|
||||
log.Printf(
|
||||
"Unexpected extension for group file %v",
|
||||
"Unexpected extension for hall file %v",
|
||||
path,
|
||||
)
|
||||
return nil
|
||||
}
|
||||
base := filepath.Base(filename)
|
||||
if base[0] == '.' {
|
||||
log.Printf("Ignoring group file %v", filename)
|
||||
log.Printf("Ignoring hall file %v", filename)
|
||||
return nil
|
||||
}
|
||||
name := strings.TrimSuffix(filename, ".json")
|
||||
desc, err := GetDescription(name)
|
||||
if err != nil {
|
||||
log.Printf("Group file %v: %v", path, err)
|
||||
log.Printf("Hall file %v: %v", path, err)
|
||||
return nil
|
||||
}
|
||||
if desc.Public {
|
||||
@@ -1273,6 +1273,6 @@ func Update() {
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Couldn't read groups: %v", err)
|
||||
log.Printf("Couldn't read halls: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package group
|
||||
package hall
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -35,21 +35,21 @@ func TestConstantTimeCompare(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGroup(t *testing.T) {
|
||||
groups.groups = nil
|
||||
Add("group", &Description{})
|
||||
Add("group/subgroup", &Description{Public: true})
|
||||
if len(groups.groups) != 2 {
|
||||
t.Errorf("Expected 2, got %v", len(groups.groups))
|
||||
halls.halls = nil
|
||||
Add("hall", &Description{})
|
||||
Add("hall/subgroup", &Description{Public: true})
|
||||
if len(halls.halls) != 2 {
|
||||
t.Errorf("Expected 2, got %v", len(halls.halls))
|
||||
}
|
||||
g := Get("group")
|
||||
g2 := Get("group/subgroup")
|
||||
g := Get("hall")
|
||||
g2 := Get("hall/subgroup")
|
||||
if g == nil {
|
||||
t.Fatalf("Couldn't get group")
|
||||
t.Fatalf("Couldn't get hall")
|
||||
}
|
||||
if g2 == nil {
|
||||
t.Fatalf("Couldn't get group/subgroup")
|
||||
t.Fatalf("Couldn't get hall/subgroup")
|
||||
}
|
||||
if name := g.Name(); name != "group" {
|
||||
if name := g.Name(); name != "hall" {
|
||||
t.Errorf("Name: expected group1, got %v", name)
|
||||
}
|
||||
if locked, _ := g.Locked(); locked {
|
||||
@@ -64,17 +64,17 @@ func TestGroup(t *testing.T) {
|
||||
t.Errorf("Expected 2, got %v", names)
|
||||
}
|
||||
|
||||
if subs := GetSubGroups("group"); len(subs) != 0 {
|
||||
if subs := GetSubGroups("hall"); len(subs) != 0 {
|
||||
t.Errorf("Expected [], got %v", subs)
|
||||
}
|
||||
|
||||
if public := GetPublic(nil); len(public) != 1 || public[0].Name != "group/subgroup" {
|
||||
t.Errorf("Expected group/subgroup, got %v", public)
|
||||
if public := GetPublic(nil); len(public) != 1 || public[0].Name != "hall/subgroup" {
|
||||
t.Errorf("Expected hall/subgroup, got %v", public)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChatHistory(t *testing.T) {
|
||||
g := Group{
|
||||
g := Hall{
|
||||
description: &Description{},
|
||||
}
|
||||
user := "user"
|
||||
@@ -213,7 +213,7 @@ var goodClients = []credPerm{
|
||||
}
|
||||
|
||||
func TestPermissions(t *testing.T) {
|
||||
var g Group
|
||||
var g Hall
|
||||
err := json.Unmarshal([]byte(desc2JSON), &g.description)
|
||||
if err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
@@ -299,7 +299,7 @@ func TestExtraPermissions(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUsernameTaken(t *testing.T) {
|
||||
var g Group
|
||||
var g Hall
|
||||
err := json.Unmarshal([]byte(desc2JSON), &g.description)
|
||||
if err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
@@ -345,7 +345,7 @@ func TestFmtpValue(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidGroupName(t *testing.T) {
|
||||
func TestValidHallName(t *testing.T) {
|
||||
type nameTest struct {
|
||||
name string
|
||||
result bool
|
||||
@@ -367,7 +367,7 @@ func TestValidGroupName(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
r := validGroupName(test.name)
|
||||
r := validHallName(test.name)
|
||||
if r != test.result {
|
||||
t.Errorf("Valid %v: got %v, expected %v",
|
||||
test.name, r, test.result)
|
||||
+17
-17
@@ -17,7 +17,7 @@ import (
|
||||
"git.stormux.org/storm/skald/codecs"
|
||||
"git.stormux.org/storm/skald/conn"
|
||||
"git.stormux.org/storm/skald/estimator"
|
||||
"git.stormux.org/storm/skald/group"
|
||||
"git.stormux.org/storm/skald/hall"
|
||||
"git.stormux.org/storm/skald/ice"
|
||||
"git.stormux.org/storm/skald/jitter"
|
||||
"git.stormux.org/storm/skald/packetcache"
|
||||
@@ -193,8 +193,8 @@ func (down *rtpDownConnection) getTracks() []*rtpDownTrack {
|
||||
return tracks
|
||||
}
|
||||
|
||||
func newDownConn(c group.Client, id string, remote conn.Up) (*rtpDownConnection, error) {
|
||||
api, err := c.Group().API()
|
||||
func newDownConn(c hall.Client, id string, remote conn.Up) (*rtpDownConnection, error) {
|
||||
api, err := c.Hall().API()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -504,7 +504,7 @@ func (up *rtpUpTrack) hasRtcpFb(tpe, parameter string) bool {
|
||||
|
||||
type rtpUpConnection struct {
|
||||
id string
|
||||
client group.Client
|
||||
client hall.Client
|
||||
label string
|
||||
pc *webrtc.PeerConnection
|
||||
iceCandidates []*webrtc.ICECandidateInit
|
||||
@@ -599,7 +599,7 @@ func (up *rtpUpConnection) flushICECandidates() error {
|
||||
}
|
||||
|
||||
// pushConnNow pushes a connection to all of the clients in a group
|
||||
func pushConnNow(up *rtpUpConnection, g *group.Group, cs []group.Client) {
|
||||
func pushConnNow(up *rtpUpConnection, g *hall.Hall, cs []hall.Client) {
|
||||
up.mu.Lock()
|
||||
up.pushed = true
|
||||
replace := up.replace
|
||||
@@ -616,12 +616,12 @@ func pushConnNow(up *rtpUpConnection, g *group.Group, cs []group.Client) {
|
||||
}
|
||||
|
||||
// pushConn schedules a call to pushConnNow
|
||||
func pushConn(up *rtpUpConnection, g *group.Group, cs []group.Client) {
|
||||
func pushConn(up *rtpUpConnection, g *hall.Hall, cs []hall.Client) {
|
||||
up.mu.Lock()
|
||||
up.pushed = false
|
||||
up.mu.Unlock()
|
||||
|
||||
go func(g *group.Group, cs []group.Client) {
|
||||
go func(g *hall.Hall, cs []hall.Client) {
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
up.mu.Lock()
|
||||
pushed := up.pushed
|
||||
@@ -633,14 +633,14 @@ func pushConn(up *rtpUpConnection, g *group.Group, cs []group.Client) {
|
||||
}(g, cs)
|
||||
}
|
||||
|
||||
func newUpConn(c group.Client, id string, label string, offer string) (*rtpUpConnection, error) {
|
||||
func newUpConn(c hall.Client, id string, label string, offer string) (*rtpUpConnection, error) {
|
||||
var o sdp.SessionDescription
|
||||
err := o.Unmarshal([]byte(offer))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
api, err := c.Group().API()
|
||||
api, err := c.Hall().API()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -686,10 +686,10 @@ func newUpConn(c group.Client, id string, label string, offer string) (*rtpUpCon
|
||||
|
||||
up.mu.Unlock()
|
||||
|
||||
pushConn(up, c.Group(), c.Group().GetClients(c))
|
||||
pushConn(up, c.Hall(), c.Hall().GetClients(c))
|
||||
})
|
||||
|
||||
pushConn(up, c.Group(), c.Group().GetClients(c))
|
||||
pushConn(up, c.Hall(), c.Hall().GetClients(c))
|
||||
go rtcpUpSender(up)
|
||||
|
||||
return up, nil
|
||||
@@ -890,7 +890,7 @@ func sadd(x, y uint64) uint64 {
|
||||
|
||||
func maxUpBitrate(t *rtpUpTrack) uint64 {
|
||||
minrate := ^uint64(0)
|
||||
maxrate := uint64(group.MinBitrate)
|
||||
maxrate := uint64(hall.MinBitrate)
|
||||
maxsid := 0
|
||||
maxtid := 0
|
||||
local := t.getLocal()
|
||||
@@ -902,8 +902,8 @@ func maxUpBitrate(t *rtpUpTrack) uint64 {
|
||||
if maxtid < tid {
|
||||
maxtid = tid
|
||||
}
|
||||
if r < group.MinBitrate {
|
||||
r = group.MinBitrate
|
||||
if r < hall.MinBitrate {
|
||||
r = hall.MinBitrate
|
||||
}
|
||||
if minrate > r {
|
||||
minrate = r
|
||||
@@ -997,14 +997,14 @@ func sendUpRTCP(up *rtpUpConnection) error {
|
||||
if t.Kind() == webrtc.RTPCodecTypeAudio {
|
||||
rate = sadd(rate, 100*1024)
|
||||
} else if t.Label() == "l" {
|
||||
rate = sadd(rate, group.LowBitrate)
|
||||
rate = sadd(rate, hall.LowBitrate)
|
||||
} else {
|
||||
rate = sadd(rate, maxUpBitrate(t))
|
||||
}
|
||||
}
|
||||
|
||||
if rate > group.MaxBitrate {
|
||||
rate = group.MaxBitrate
|
||||
if rate > hall.MaxBitrate {
|
||||
rate = hall.MaxBitrate
|
||||
}
|
||||
if len(ssrcs) > 0 {
|
||||
packets = append(packets,
|
||||
|
||||
+103
-103
@@ -20,7 +20,7 @@ import (
|
||||
"git.stormux.org/storm/skald/conn"
|
||||
"git.stormux.org/storm/skald/diskwriter"
|
||||
"git.stormux.org/storm/skald/estimator"
|
||||
"git.stormux.org/storm/skald/group"
|
||||
"git.stormux.org/storm/skald/hall"
|
||||
"git.stormux.org/storm/skald/ice"
|
||||
"git.stormux.org/storm/skald/token"
|
||||
"git.stormux.org/storm/skald/unbounded"
|
||||
@@ -33,7 +33,7 @@ func errorToWSCloseMessage(id string, err error) (*clientMessage, []byte) {
|
||||
switch e := err.(type) {
|
||||
case *websocket.CloseError:
|
||||
code = websocket.CloseNormalClosure
|
||||
case group.ProtocolError:
|
||||
case hall.ProtocolError:
|
||||
code = websocket.CloseProtocolError
|
||||
m = &clientMessage{
|
||||
Type: "usermessage",
|
||||
@@ -43,7 +43,7 @@ func errorToWSCloseMessage(id string, err error) (*clientMessage, []byte) {
|
||||
Value: e.Error(),
|
||||
}
|
||||
text = e.Error()
|
||||
case group.UserError, group.KickError:
|
||||
case hall.UserError, hall.KickError:
|
||||
code = websocket.CloseNormalClosure
|
||||
m = errorMessage(id, err)
|
||||
text = e.Error()
|
||||
@@ -60,7 +60,7 @@ func isWSNormalError(err error) bool {
|
||||
}
|
||||
|
||||
type webClient struct {
|
||||
group *group.Group
|
||||
hall *hall.Hall
|
||||
addr net.Addr
|
||||
id string
|
||||
username string
|
||||
@@ -77,8 +77,8 @@ type webClient struct {
|
||||
up map[string]*rtpUpConnection
|
||||
}
|
||||
|
||||
func (c *webClient) Group() *group.Group {
|
||||
return c.group
|
||||
func (c *webClient) Hall() *hall.Hall {
|
||||
return c.hall
|
||||
}
|
||||
|
||||
func (c *webClient) Addr() net.Addr {
|
||||
@@ -130,7 +130,7 @@ type clientMessage struct {
|
||||
Token string `json:"token,omitempty"`
|
||||
Privileged bool `json:"privileged,omitempty"`
|
||||
Permissions []string `json:"permissions,omitempty"`
|
||||
Status *group.Status `json:"status,omitempty"`
|
||||
Status *hall.Status `json:"status,omitempty"`
|
||||
Data map[string]interface{} `json:"data,omitempty"`
|
||||
Group string `json:"group,omitempty"`
|
||||
Value interface{} `json:"value,omitempty"`
|
||||
@@ -229,7 +229,7 @@ func delUpConn(c *webClient, id string, userId string, push bool) error {
|
||||
replace := conn.getReplace(false)
|
||||
|
||||
delete(c.up, id)
|
||||
g := c.group
|
||||
g := c.hall
|
||||
c.mu.Unlock()
|
||||
|
||||
conn.mu.Lock()
|
||||
@@ -386,9 +386,9 @@ func addDownTrackUnlocked(conn *rtpDownConnection, remoteTrack *rtpUpTrack) erro
|
||||
// replace the RTCP feedback types with the ones we understand
|
||||
remoteCodec := remoteTrack.Codec()
|
||||
if strings.HasPrefix(strings.ToLower(remoteCodec.MimeType), "video/") {
|
||||
remoteCodec.RTCPFeedback = group.VideoRTCPFeedback
|
||||
remoteCodec.RTCPFeedback = hall.VideoRTCPFeedback
|
||||
} else {
|
||||
remoteCodec.RTCPFeedback = group.AudioRTCPFeedback
|
||||
remoteCodec.RTCPFeedback = hall.AudioRTCPFeedback
|
||||
}
|
||||
|
||||
local, err := webrtc.NewTrackLocalStaticRTP(
|
||||
@@ -408,7 +408,7 @@ func addDownTrackUnlocked(conn *rtpDownConnection, remoteTrack *rtpUpTrack) erro
|
||||
}
|
||||
|
||||
codec := local.Codec()
|
||||
ptype, err := group.CodecPayloadType(local.Codec())
|
||||
ptype, err := hall.CodecPayloadType(local.Codec())
|
||||
if err != nil {
|
||||
log.Printf("Couldn't determine ptype for codec %v: %v",
|
||||
codec.MimeType, err)
|
||||
@@ -726,31 +726,31 @@ func parseRequested(r interface{}) (map[string][]string, error) {
|
||||
}
|
||||
|
||||
func (c *webClient) setRequested(requested map[string][]string) error {
|
||||
if c.group == nil {
|
||||
if c.hall == nil {
|
||||
return errors.New("attempted to request with no group joined")
|
||||
}
|
||||
c.requested = requested
|
||||
|
||||
requestConns(c, c.group, "")
|
||||
requestConns(c, c.hall, "")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *webClient) setRequestedStream(down *rtpDownConnection, requested []string) error {
|
||||
var remoteClient group.Client
|
||||
var remoteClient hall.Client
|
||||
remote, ok := down.remote.(*rtpUpConnection)
|
||||
if ok {
|
||||
remoteClient = remote.client
|
||||
}
|
||||
down.requested = requested
|
||||
return remoteClient.RequestConns(c, c.group, remote.id)
|
||||
return remoteClient.RequestConns(c, c.hall, remote.id)
|
||||
}
|
||||
|
||||
func (c *webClient) RequestConns(target group.Client, g *group.Group, id string) error {
|
||||
func (c *webClient) RequestConns(target hall.Client, g *hall.Hall, id string) error {
|
||||
c.action(requestConnsAction{g, target, id})
|
||||
return nil
|
||||
}
|
||||
|
||||
func requestConns(target group.Client, g *group.Group, id string) {
|
||||
func requestConns(target hall.Client, g *hall.Hall, id string) {
|
||||
clients := g.GetClients(target)
|
||||
for _, c := range clients {
|
||||
c.RequestConns(target, g, id)
|
||||
@@ -817,7 +817,7 @@ func requestedTracks(c *webClient, requested []string, tracks []conn.UpTrack) ([
|
||||
return ts, limitSid
|
||||
}
|
||||
|
||||
func (c *webClient) PushConn(g *group.Group, id string, up conn.Up, tracks []conn.UpTrack, replace string) error {
|
||||
func (c *webClient) PushConn(g *hall.Hall, id string, up conn.Up, tracks []conn.UpTrack, replace string) error {
|
||||
c.action(pushConnAction{g, id, up, tracks, replace})
|
||||
return nil
|
||||
}
|
||||
@@ -854,7 +854,7 @@ func StartClient(conn *websocket.Conn, addr net.Addr) (err error) {
|
||||
),
|
||||
)
|
||||
conn.Close()
|
||||
err = group.ProtocolError("client didn't handshake")
|
||||
err = hall.ProtocolError("client didn't handshake")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -883,7 +883,7 @@ func StartClient(conn *websocket.Conn, addr net.Addr) (err error) {
|
||||
m, e := errorToWSCloseMessage(c.id, err)
|
||||
if isWSNormalError(err) {
|
||||
err = nil
|
||||
} else if _, ok := err.(group.KickError); ok {
|
||||
} else if _, ok := err.(hall.KickError); ok {
|
||||
err = nil
|
||||
}
|
||||
if m != nil {
|
||||
@@ -896,7 +896,7 @@ func StartClient(conn *websocket.Conn, addr net.Addr) (err error) {
|
||||
}
|
||||
|
||||
type pushConnAction struct {
|
||||
group *group.Group
|
||||
hall *hall.Hall
|
||||
id string
|
||||
conn conn.Up
|
||||
tracks []conn.UpTrack
|
||||
@@ -904,8 +904,8 @@ type pushConnAction struct {
|
||||
}
|
||||
|
||||
type requestConnsAction struct {
|
||||
group *group.Group
|
||||
target group.Client
|
||||
hall *hall.Hall
|
||||
target hall.Client
|
||||
id string
|
||||
}
|
||||
|
||||
@@ -939,7 +939,7 @@ type kickAction struct {
|
||||
message string
|
||||
}
|
||||
|
||||
var errEmptyId = group.ProtocolError("empty id")
|
||||
var errEmptyId = hall.ProtocolError("empty id")
|
||||
|
||||
func member(v string, l []string) bool {
|
||||
for _, w := range l {
|
||||
@@ -1108,14 +1108,14 @@ func pushDownConn(c *webClient, id string, up conn.Up, tracks []conn.UpTrack, re
|
||||
func handleAction(c *webClient, a any) error {
|
||||
switch a := a.(type) {
|
||||
case pushConnAction:
|
||||
if c.group == nil || c.group != a.group {
|
||||
if c.hall == nil || c.hall != a.hall {
|
||||
log.Printf("Got connectsions for wrong group")
|
||||
return nil
|
||||
}
|
||||
return pushDownConn(c, a.id, a.conn, a.tracks, a.replace)
|
||||
case requestConnsAction:
|
||||
g := c.group
|
||||
if g == nil || a.group != g {
|
||||
g := c.hall
|
||||
if g == nil || a.hall != g {
|
||||
log.Printf("Misdirected pushConns")
|
||||
return nil
|
||||
}
|
||||
@@ -1148,7 +1148,7 @@ func handleAction(c *webClient, a any) error {
|
||||
tracks[i] = t.remote
|
||||
}
|
||||
c.PushConn(
|
||||
c.group,
|
||||
c.hall,
|
||||
down.remote.Id(), down.remote,
|
||||
tracks, "",
|
||||
)
|
||||
@@ -1163,8 +1163,8 @@ func handleAction(c *webClient, a any) error {
|
||||
}
|
||||
|
||||
case pushClientAction:
|
||||
if a.group != c.group.Name() {
|
||||
log.Printf("got client for wrong group")
|
||||
if a.group != c.hall.Name() {
|
||||
log.Printf("got client for wrong hall")
|
||||
return nil
|
||||
}
|
||||
perms := append([]string(nil), a.permissions...)
|
||||
@@ -1178,11 +1178,11 @@ func handleAction(c *webClient, a any) error {
|
||||
Data: a.data,
|
||||
})
|
||||
case joinedAction:
|
||||
var status *group.Status
|
||||
var status *hall.Status
|
||||
var data map[string]interface{}
|
||||
var g *group.Group
|
||||
var g *hall.Hall
|
||||
if a.group != "" {
|
||||
g = group.Get(a.group)
|
||||
g = hall.Get(a.group)
|
||||
if g != nil {
|
||||
s := g.Status(true, nil)
|
||||
status = &s
|
||||
@@ -1230,7 +1230,7 @@ func handleAction(c *webClient, a any) error {
|
||||
switch a.kind {
|
||||
case "op":
|
||||
c.permissions = addnew("op", c.permissions)
|
||||
g := c.Group()
|
||||
g := c.Hall()
|
||||
if g != nil && g.Description().AllowRecording {
|
||||
c.permissions = addnew("record", c.permissions)
|
||||
}
|
||||
@@ -1246,11 +1246,11 @@ func handleAction(c *webClient, a any) error {
|
||||
case "unshutup":
|
||||
c.permissions = addnew("message", c.permissions)
|
||||
default:
|
||||
return group.UserError("unknown permission")
|
||||
return hall.UserError("unknown permission")
|
||||
}
|
||||
c.action(permissionsChangedAction{})
|
||||
case permissionsChangedAction:
|
||||
g := c.Group()
|
||||
g := c.Hall()
|
||||
if g == nil {
|
||||
return errors.New("Permissions changed in no group")
|
||||
}
|
||||
@@ -1284,7 +1284,7 @@ func handleAction(c *webClient, a any) error {
|
||||
user := c.Username()
|
||||
d := c.Data()
|
||||
clients := g.GetClients(nil)
|
||||
go func(clients []group.Client) {
|
||||
go func(clients []hall.Client) {
|
||||
for _, cc := range clients {
|
||||
cc.PushClient(
|
||||
g.Name(), "change", id, user, perms, d,
|
||||
@@ -1292,7 +1292,7 @@ func handleAction(c *webClient, a any) error {
|
||||
}
|
||||
}(clients)
|
||||
case kickAction:
|
||||
return group.KickError{
|
||||
return hall.KickError{
|
||||
a.id, a.username, a.message,
|
||||
}
|
||||
default:
|
||||
@@ -1313,7 +1313,7 @@ func failUpConnection(c *webClient, id string, message string) error {
|
||||
}
|
||||
}
|
||||
if message != "" {
|
||||
err := c.error(group.UserError(message))
|
||||
err := c.error(hall.UserError(message))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1322,7 +1322,7 @@ func failUpConnection(c *webClient, id string, message string) error {
|
||||
}
|
||||
|
||||
func leaveGroup(c *webClient) {
|
||||
if c.group == nil {
|
||||
if c.hall == nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1337,11 +1337,11 @@ func leaveGroup(c *webClient) {
|
||||
}
|
||||
}
|
||||
|
||||
group.DelClient(c)
|
||||
hall.DelClient(c)
|
||||
c.permissions = nil
|
||||
c.data = nil
|
||||
c.requested = make(map[string][]string)
|
||||
c.group = nil
|
||||
c.hall = nil
|
||||
}
|
||||
|
||||
func closeDownConn(c *webClient, id string, message string) error {
|
||||
@@ -1357,7 +1357,7 @@ func closeDownConn(c *webClient, id string, message string) error {
|
||||
return err
|
||||
}
|
||||
if message != "" {
|
||||
err := c.error(group.UserError(message))
|
||||
err := c.error(hall.UserError(message))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1375,10 +1375,10 @@ func (c *webClient) Joined(group, kind string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func kickClient(g *group.Group, id string, user *string, dest string, message string) error {
|
||||
func kickClient(g *hall.Hall, id string, user *string, dest string, message string) error {
|
||||
client := g.GetClient(dest)
|
||||
if client == nil {
|
||||
return group.UserError("no such user")
|
||||
return hall.UserError("no such user")
|
||||
}
|
||||
|
||||
return client.Kick(id, user, message)
|
||||
@@ -1387,14 +1387,14 @@ func kickClient(g *group.Group, id string, user *string, dest string, message st
|
||||
func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
if m.Source != "" {
|
||||
if m.Source != c.Id() {
|
||||
return group.ProtocolError("spoofed client id")
|
||||
return hall.ProtocolError("spoofed client id")
|
||||
}
|
||||
}
|
||||
|
||||
if m.Type != "join" {
|
||||
if m.Username != nil {
|
||||
if *m.Username != c.Username() {
|
||||
return group.ProtocolError("spoofed username")
|
||||
return hall.ProtocolError("spoofed username")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1402,25 +1402,25 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
switch m.Type {
|
||||
case "join":
|
||||
if m.Kind == "leave" {
|
||||
if c.group == nil || c.group.Name() != m.Group {
|
||||
return group.UserError("you are not joined")
|
||||
if c.hall == nil || c.hall.Name() != m.Group {
|
||||
return hall.UserError("you are not joined")
|
||||
}
|
||||
leaveGroup(c)
|
||||
return nil
|
||||
}
|
||||
|
||||
if m.Kind != "join" {
|
||||
return group.ProtocolError("unknown kind")
|
||||
return hall.ProtocolError("unknown kind")
|
||||
}
|
||||
|
||||
if c.group != nil {
|
||||
return group.ProtocolError(
|
||||
if c.hall != nil {
|
||||
return hall.ProtocolError(
|
||||
"cannot join multiple groups",
|
||||
)
|
||||
}
|
||||
c.data = m.Data
|
||||
g, err := group.AddClient(m.Group, c,
|
||||
group.ClientCredentials{
|
||||
g, err := hall.AddClient(m.Group, c,
|
||||
hall.ClientCredentials{
|
||||
Username: m.Username,
|
||||
Password: m.Password,
|
||||
Token: m.Token,
|
||||
@@ -1428,11 +1428,11 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
)
|
||||
if err != nil {
|
||||
var e, s string
|
||||
var autherr *group.NotAuthorisedError
|
||||
var autherr *hall.NotAuthorisedError
|
||||
if errors.Is(err, token.ErrUsernameRequired) {
|
||||
s = err.Error()
|
||||
e = "need-username"
|
||||
} else if errors.Is(err, group.ErrDuplicateUsername) {
|
||||
} else if errors.Is(err, hall.ErrDuplicateUsername) {
|
||||
s = err.Error()
|
||||
e = "duplicate-username"
|
||||
} else if errors.As(err, &autherr) {
|
||||
@@ -1441,7 +1441,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
log.Printf("Join group: %v", err)
|
||||
} else if errors.Is(err, os.ErrNotExist) {
|
||||
s = "group does not exist"
|
||||
} else if _, ok := err.(group.UserError); ok {
|
||||
} else if _, ok := err.(hall.UserError); ok {
|
||||
s = err.Error()
|
||||
} else {
|
||||
s = "internal server error"
|
||||
@@ -1469,7 +1469,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
Value: redirect,
|
||||
})
|
||||
}
|
||||
c.group = g
|
||||
c.hall = g
|
||||
case "request":
|
||||
requested, err := parseRequested(m.Request)
|
||||
if err != nil {
|
||||
@@ -1498,7 +1498,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
Type: "abort",
|
||||
Id: m.Id,
|
||||
})
|
||||
return c.error(group.UserError("not authorised"))
|
||||
return c.error(hall.UserError("not authorised"))
|
||||
}
|
||||
err := gotOffer(c, m.Id, m.Label, m.SDP, m.Replace)
|
||||
if err != nil {
|
||||
@@ -1565,16 +1565,16 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
return errEmptyId
|
||||
}
|
||||
if m.Candidate == nil {
|
||||
return group.ProtocolError("null candidate")
|
||||
return hall.ProtocolError("null candidate")
|
||||
}
|
||||
err := gotICE(c, m.Candidate, m.Id)
|
||||
if err != nil {
|
||||
log.Printf("ICE: %v", err)
|
||||
}
|
||||
case "chat", "usermessage":
|
||||
g := c.group
|
||||
g := c.hall
|
||||
if g == nil {
|
||||
return c.error(group.UserError("join a group first"))
|
||||
return c.error(hall.UserError("join a group first"))
|
||||
}
|
||||
|
||||
required := "message"
|
||||
@@ -1582,7 +1582,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
required = "caption"
|
||||
}
|
||||
if !member(required, c.permissions) {
|
||||
return c.error(group.UserError("not authorised"))
|
||||
return c.error(hall.UserError("not authorised"))
|
||||
}
|
||||
|
||||
id := m.Id
|
||||
@@ -1614,7 +1614,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
Value: m.Value,
|
||||
}
|
||||
if m.Dest == "" {
|
||||
var except group.Client
|
||||
var except hall.Client
|
||||
if m.NoEcho {
|
||||
except = c
|
||||
}
|
||||
@@ -1625,38 +1625,38 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
} else {
|
||||
cc := g.GetClient(m.Dest)
|
||||
if cc == nil {
|
||||
return c.error(group.UserError("user unknown"))
|
||||
return c.error(hall.UserError("user unknown"))
|
||||
}
|
||||
ccc, ok := cc.(*webClient)
|
||||
if !ok {
|
||||
return c.error(group.UserError(
|
||||
return c.error(hall.UserError(
|
||||
"this user doesn't chat",
|
||||
))
|
||||
}
|
||||
ccc.write(mm)
|
||||
}
|
||||
case "groupaction":
|
||||
g := c.group
|
||||
g := c.hall
|
||||
if g == nil {
|
||||
return c.error(group.UserError("join a group first"))
|
||||
return c.error(hall.UserError("join a group first"))
|
||||
}
|
||||
switch m.Kind {
|
||||
case "clearchat":
|
||||
if !member("op", c.permissions) {
|
||||
return c.error(group.UserError("not authorised"))
|
||||
return c.error(hall.UserError("not authorised"))
|
||||
}
|
||||
var id, userId string
|
||||
if m.Value != nil {
|
||||
value, ok := m.Value.(map[string]any)
|
||||
if !ok {
|
||||
return c.error(group.UserError(
|
||||
return c.error(hall.UserError(
|
||||
"bad value in clearchat",
|
||||
))
|
||||
}
|
||||
id, _ = value["id"].(string)
|
||||
userId, _ = value["userId"].(string)
|
||||
if userId == "" && id != "" {
|
||||
return c.error(group.UserError(
|
||||
return c.error(hall.UserError(
|
||||
"bad value in clearchat",
|
||||
))
|
||||
}
|
||||
@@ -1674,7 +1674,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
}
|
||||
case "lock", "unlock":
|
||||
if !member("op", c.permissions) {
|
||||
return c.error(group.UserError("not authorised"))
|
||||
return c.error(hall.UserError("not authorised"))
|
||||
}
|
||||
message := ""
|
||||
v, ok := m.Value.(string)
|
||||
@@ -1684,17 +1684,17 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
g.SetLocked(m.Kind == "lock", message)
|
||||
case "record":
|
||||
if !member("record", c.permissions) {
|
||||
return c.error(group.UserError("not authorised"))
|
||||
return c.error(hall.UserError("not authorised"))
|
||||
}
|
||||
for _, cc := range g.GetClients(c) {
|
||||
_, ok := cc.(*diskwriter.Client)
|
||||
if ok {
|
||||
return c.error(group.UserError("already recording"))
|
||||
return c.error(hall.UserError("already recording"))
|
||||
}
|
||||
}
|
||||
disk := diskwriter.New(g)
|
||||
_, err := group.AddClient(g.Name(), disk,
|
||||
group.ClientCredentials{
|
||||
_, err := hall.AddClient(g.Name(), disk,
|
||||
hall.ClientCredentials{
|
||||
System: true,
|
||||
},
|
||||
)
|
||||
@@ -1702,24 +1702,24 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
disk.Close()
|
||||
return c.error(err)
|
||||
}
|
||||
requestConns(disk, c.group, "")
|
||||
requestConns(disk, c.hall, "")
|
||||
case "unrecord":
|
||||
if !member("record", c.permissions) {
|
||||
return c.error(group.UserError("not authorised"))
|
||||
return c.error(hall.UserError("not authorised"))
|
||||
}
|
||||
for _, cc := range g.GetClients(c) {
|
||||
disk, ok := cc.(*diskwriter.Client)
|
||||
if ok {
|
||||
disk.Close()
|
||||
group.DelClient(disk)
|
||||
hall.DelClient(disk)
|
||||
}
|
||||
}
|
||||
case "subgroups":
|
||||
if !member("op", c.permissions) {
|
||||
return c.error(group.UserError("not authorised"))
|
||||
return c.error(hall.UserError("not authorised"))
|
||||
}
|
||||
s := ""
|
||||
for _, sg := range group.GetSubGroups(g.Name()) {
|
||||
for _, sg := range hall.GetSubGroups(g.Name()) {
|
||||
plural := ""
|
||||
if sg.Clients > 1 {
|
||||
plural = "s"
|
||||
@@ -1737,11 +1737,11 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
})
|
||||
case "setdata":
|
||||
if !member("op", c.permissions) {
|
||||
return c.error(group.UserError("not authorised"))
|
||||
return c.error(hall.UserError("not authorised"))
|
||||
}
|
||||
data, ok := m.Value.(map[string]interface{})
|
||||
if !ok {
|
||||
return c.error(group.UserError(
|
||||
return c.error(hall.UserError(
|
||||
"Bad value in setdata",
|
||||
))
|
||||
}
|
||||
@@ -1773,7 +1773,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
return terror("error", "client specified token")
|
||||
}
|
||||
|
||||
if tok.Group != c.group.Name() {
|
||||
if tok.Group != c.hall.Name() {
|
||||
return terror("error", "wrong group in token")
|
||||
}
|
||||
if tok.IncludeSubgroups {
|
||||
@@ -1786,7 +1786,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
}
|
||||
|
||||
if tok.Username != nil &&
|
||||
c.group.UserExists(*tok.Username) {
|
||||
c.hall.UserExists(*tok.Username) {
|
||||
return terror("error", "that username is taken")
|
||||
}
|
||||
|
||||
@@ -1881,7 +1881,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
!member("token", c.permissions) {
|
||||
return terror("not-authorised", "not authorised")
|
||||
}
|
||||
tokens, _, err := token.List(c.group.Name())
|
||||
tokens, _, err := token.List(c.hall.Name())
|
||||
if err != nil {
|
||||
return terror("error", err.Error())
|
||||
}
|
||||
@@ -1892,37 +1892,37 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
Value: tokens,
|
||||
})
|
||||
default:
|
||||
return group.UserError("unknown group action")
|
||||
return hall.UserError("unknown group action")
|
||||
}
|
||||
case "useraction":
|
||||
g := c.group
|
||||
g := c.hall
|
||||
if g == nil {
|
||||
return c.error(group.UserError("join a group first"))
|
||||
return c.error(hall.UserError("join a group first"))
|
||||
}
|
||||
switch m.Kind {
|
||||
case "op", "unop", "present", "unpresent", "shutup", "unshutup":
|
||||
if !member("op", c.permissions) {
|
||||
return c.error(group.UserError("not authorised"))
|
||||
return c.error(hall.UserError("not authorised"))
|
||||
}
|
||||
t := g.GetClient(m.Dest)
|
||||
if t == nil {
|
||||
return c.error(group.UserError("no such user"))
|
||||
return c.error(hall.UserError("no such user"))
|
||||
}
|
||||
target, ok := t.(*webClient)
|
||||
if !ok {
|
||||
return c.error(group.UserError(
|
||||
return c.error(hall.UserError(
|
||||
"this is not a real user",
|
||||
))
|
||||
}
|
||||
target.action(changePermissionsAction{m.Kind})
|
||||
case "identify":
|
||||
if !member("op", c.permissions) {
|
||||
return c.error(group.UserError("not authorised"))
|
||||
return c.error(hall.UserError("not authorised"))
|
||||
}
|
||||
d := g.GetClient(m.Dest)
|
||||
if d == nil {
|
||||
return c.error(
|
||||
group.UserError("client not found"),
|
||||
hall.UserError("client not found"),
|
||||
)
|
||||
}
|
||||
value := make(map[string]any)
|
||||
@@ -1950,7 +1950,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
})
|
||||
case "kick":
|
||||
if !member("op", c.permissions) {
|
||||
return c.error(group.UserError("not authorised"))
|
||||
return c.error(hall.UserError("not authorised"))
|
||||
}
|
||||
message := ""
|
||||
v, ok := m.Value.(string)
|
||||
@@ -1963,11 +1963,11 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
}
|
||||
case "setdata":
|
||||
if m.Dest != c.Id() {
|
||||
return c.error(group.UserError("not authorised"))
|
||||
return c.error(hall.UserError("not authorised"))
|
||||
}
|
||||
data, ok := m.Value.(map[string]interface{})
|
||||
if !ok {
|
||||
return c.error(group.UserError(
|
||||
return c.error(hall.UserError(
|
||||
"Bad value in setdata",
|
||||
))
|
||||
}
|
||||
@@ -1985,7 +1985,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
user := c.Username()
|
||||
perms := c.Permissions()
|
||||
data = c.Data()
|
||||
go func(clients []group.Client) {
|
||||
go func(clients []hall.Client) {
|
||||
for _, cc := range clients {
|
||||
cc.PushClient(
|
||||
g.Name(), "change",
|
||||
@@ -1994,7 +1994,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
}
|
||||
}(g.GetClients(nil))
|
||||
default:
|
||||
return group.UserError("unknown user action")
|
||||
return hall.UserError("unknown user action")
|
||||
}
|
||||
case "pong":
|
||||
// nothing
|
||||
@@ -2004,7 +2004,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||
})
|
||||
default:
|
||||
log.Printf("unexpected message: %v", m.Type)
|
||||
return group.ProtocolError("unexpected message")
|
||||
return hall.ProtocolError("unexpected message")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -2199,7 +2199,7 @@ func (c *webClient) write(m clientMessage) error {
|
||||
}
|
||||
}
|
||||
|
||||
func broadcast(cs []group.Client, m clientMessage) error {
|
||||
func broadcast(cs []hall.Client, m clientMessage) error {
|
||||
b, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -2228,7 +2228,7 @@ func (c *webClient) close(data []byte) error {
|
||||
|
||||
func errorMessage(id string, err error) *clientMessage {
|
||||
switch e := err.(type) {
|
||||
case group.UserError:
|
||||
case hall.UserError:
|
||||
return &clientMessage{
|
||||
Type: "usermessage",
|
||||
Kind: "error",
|
||||
@@ -2236,7 +2236,7 @@ func errorMessage(id string, err error) *clientMessage {
|
||||
Privileged: true,
|
||||
Value: e.Error(),
|
||||
}
|
||||
case group.KickError:
|
||||
case hall.KickError:
|
||||
message := e.Message
|
||||
if message == "" {
|
||||
message = "you have been kicked out"
|
||||
|
||||
+12
-12
@@ -7,7 +7,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"git.stormux.org/storm/skald/conn"
|
||||
"git.stormux.org/storm/skald/group"
|
||||
"git.stormux.org/storm/skald/hall"
|
||||
"git.stormux.org/storm/skald/sdpfrag"
|
||||
|
||||
"github.com/pion/sdp/v3"
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
type WhipClient struct {
|
||||
group *group.Group
|
||||
hall *hall.Hall
|
||||
addr net.Addr
|
||||
id string
|
||||
token string
|
||||
@@ -27,12 +27,12 @@ type WhipClient struct {
|
||||
etag string
|
||||
}
|
||||
|
||||
func NewWhipClient(g *group.Group, id string, token string, addr net.Addr) *WhipClient {
|
||||
return &WhipClient{group: g, id: id, token: token, addr: addr}
|
||||
func NewWhipClient(g *hall.Hall, id string, token string, addr net.Addr) *WhipClient {
|
||||
return &WhipClient{hall: g, id: id, token: token, addr: addr}
|
||||
}
|
||||
|
||||
func (c *WhipClient) Group() *group.Group {
|
||||
return c.group
|
||||
func (c *WhipClient) Hall() *hall.Hall {
|
||||
return c.hall
|
||||
}
|
||||
|
||||
func (c *WhipClient) Addr() net.Addr {
|
||||
@@ -83,12 +83,12 @@ func (c *WhipClient) SetETag(etag string) {
|
||||
c.etag = etag
|
||||
}
|
||||
|
||||
func (c *WhipClient) PushConn(g *group.Group, id string, conn conn.Up, tracks []conn.UpTrack, replace string) error {
|
||||
func (c *WhipClient) PushConn(g *hall.Hall, id string, conn conn.Up, tracks []conn.UpTrack, replace string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *WhipClient) RequestConns(target group.Client, g *group.Group, id string) error {
|
||||
if g != c.group {
|
||||
func (c *WhipClient) RequestConns(target hall.Client, g *hall.Hall, id string) error {
|
||||
if g != c.hall {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ func (c *WhipClient) Kick(id string, user *string, message string) error {
|
||||
func (c *WhipClient) Close() error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
g := c.group
|
||||
g := c.hall
|
||||
if g == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -136,8 +136,8 @@ func (c *WhipClient) Close() error {
|
||||
}
|
||||
c.connection = nil
|
||||
}
|
||||
group.DelClient(c)
|
||||
c.group = nil
|
||||
hall.DelClient(c)
|
||||
c.hall = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
# Skald's administrative API
|
||||
|
||||
Skald provides an HTTP-based API that can be used to create groups and
|
||||
Skald provides an HTTP-based API that can be used to create halls and
|
||||
users. For example, in order to create a hall, a client may do
|
||||
|
||||
PUT /skald-api/v0/.halls/hallname/
|
||||
@@ -39,11 +39,11 @@ Provides a number of statistics about the running server, in JSON. The
|
||||
exact format is undocumented, and may change between versions. The only
|
||||
allowed methods are HEAD and GET.
|
||||
|
||||
### List of groups
|
||||
### List of halls
|
||||
|
||||
/skald-api/v0/.halls/
|
||||
|
||||
Returns a list of groups, as a JSON array. The only allowed methods are
|
||||
Returns a list of halls, as a JSON array. The only allowed methods are
|
||||
HEAD and GET.
|
||||
|
||||
### Group definition
|
||||
|
||||
+4
-4
@@ -56,17 +56,17 @@ The following instructions assume that your server is called
|
||||
`skald.example.org` and that you have already created a dedicated user
|
||||
called `skald`.
|
||||
|
||||
First, make sure that the `groups` and `data` directories exist:
|
||||
First, make sure that the `halls` and `data` directories exist:
|
||||
|
||||
```sh
|
||||
mkdir groups data
|
||||
mkdir halls data
|
||||
```
|
||||
|
||||
Now copy the `skald` binary, and the directories `static`, `data` and
|
||||
`groups` to the server:
|
||||
`halls` to the server:
|
||||
|
||||
```sh
|
||||
rsync -a skald static data groups skald@skald.example.org:
|
||||
rsync -a skald static data halls skald@skald.example.org:
|
||||
```
|
||||
|
||||
If you don't have a TLS certificate, Skald will generate a self-signed
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"time"
|
||||
|
||||
"git.stormux.org/storm/skald/diskwriter"
|
||||
"git.stormux.org/storm/skald/group"
|
||||
"git.stormux.org/storm/skald/hall"
|
||||
"git.stormux.org/storm/skald/ice"
|
||||
"git.stormux.org/storm/skald/limit"
|
||||
"git.stormux.org/storm/skald/token"
|
||||
@@ -32,10 +32,10 @@ func main() {
|
||||
"web server root `directory`")
|
||||
flag.BoolVar(&webserver.Insecure, "insecure", false,
|
||||
"act as an HTTP server rather than HTTPS")
|
||||
flag.StringVar(&group.DataDirectory, "data", "./data/",
|
||||
flag.StringVar(&hall.DataDirectory, "data", "./data/",
|
||||
"data `directory`")
|
||||
flag.StringVar(&group.Directory, "groups", "./groups/",
|
||||
"group description `directory`")
|
||||
flag.StringVar(&hall.Directory, "halls", "./halls/",
|
||||
"hall description `directory`")
|
||||
flag.StringVar(&diskwriter.Directory, "recordings", "./recordings/",
|
||||
"recordings `directory`")
|
||||
flag.StringVar(&cpuprofile, "cpuprofile", "",
|
||||
@@ -46,7 +46,7 @@ func main() {
|
||||
"store mutex profile in `file`")
|
||||
flag.StringVar(&udpRange, "udp-range", "",
|
||||
"UDP `port` (multiplexing) or port1-port2 (range)")
|
||||
flag.BoolVar(&group.UseMDNS, "mdns", false, "gather mDNS addresses")
|
||||
flag.BoolVar(&hall.UseMDNS, "mdns", false, "gather mDNS addresses")
|
||||
flag.BoolVar(&ice.ICERelayOnly, "relay-only", false,
|
||||
"require use of TURN relays for all media traffic")
|
||||
flag.StringVar(&turnserver.Address, "turn", "auto",
|
||||
@@ -63,14 +63,14 @@ func main() {
|
||||
if n != 2 || min <= 0 || max <= 0 || min > max {
|
||||
log.Fatalf("UDP range: bad range")
|
||||
}
|
||||
group.UDPMin = min
|
||||
group.UDPMax = max
|
||||
hall.UDPMin = min
|
||||
hall.UDPMax = max
|
||||
} else {
|
||||
port, err := strconv.Atoi(udpRange)
|
||||
if err != nil {
|
||||
log.Fatalf("UDP: %v", err)
|
||||
}
|
||||
err = group.SetUDPMux(port)
|
||||
err = hall.SetUDPMux(port)
|
||||
if err != nil {
|
||||
log.Fatalf("UDP: %v", err)
|
||||
}
|
||||
@@ -122,22 +122,22 @@ func main() {
|
||||
log.Printf("File descriptor limit is %v, please increase it!", n)
|
||||
}
|
||||
|
||||
ice.ICEFilename = filepath.Join(group.DataDirectory, "ice-servers.json")
|
||||
ice.ICEFilename = filepath.Join(hall.DataDirectory, "ice-servers.json")
|
||||
token.SetStatefulFilename(
|
||||
filepath.Join(
|
||||
filepath.Join(group.DataDirectory, "var"),
|
||||
filepath.Join(hall.DataDirectory, "var"),
|
||||
"tokens.jsonl",
|
||||
),
|
||||
)
|
||||
|
||||
// make sure the list of public groups is updated early
|
||||
go group.Update()
|
||||
// make sure the list of public halls is updated early
|
||||
go hall.Update()
|
||||
|
||||
// causes the built-in server to start if required
|
||||
ice.Update()
|
||||
defer turnserver.Stop()
|
||||
|
||||
err = webserver.Serve(httpAddr, group.DataDirectory)
|
||||
err = webserver.Serve(httpAddr, hall.DataDirectory)
|
||||
if err != nil {
|
||||
log.Fatalf("Server: %v", err)
|
||||
}
|
||||
@@ -157,7 +157,7 @@ func main() {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
go func() {
|
||||
group.Update()
|
||||
hall.Update()
|
||||
token.Expire()
|
||||
}()
|
||||
case <-slowTicker.C:
|
||||
|
||||
@@ -177,23 +177,23 @@ fields are as follows:
|
||||
will be redirected to the canonical one.
|
||||
|
||||
|
||||
## Group definitions
|
||||
## Hall definitions
|
||||
|
||||
Groups are described by JSON files in the `groups/` directory. These
|
||||
Halls are described by JSON files in the `halls/` directory. These
|
||||
files are normally administered using the `skaldctl` utility, but may
|
||||
also be edited manually (there is no need to restart the server).
|
||||
|
||||
### Managing groups using `skaldctl`
|
||||
### Managing halls using `skaldctl`
|
||||
|
||||
#### Creating, modifying, and deleting groups
|
||||
#### Creating, modifying, and deleting halls
|
||||
|
||||
A group is created using `skaldctl create-hall`:
|
||||
A hall is created using `skaldctl create-hall`:
|
||||
|
||||
```sh
|
||||
skaldctl create-hall -hall city-watch
|
||||
```
|
||||
|
||||
There are a number of options to customise the behaviour of the group, see
|
||||
There are a number of options to customise the behaviour of the hall, see
|
||||
`skaldctl create-hall -help` for a full list. For example, in order to
|
||||
create a hall that allows unrestricted creation of tokens, say:
|
||||
|
||||
@@ -203,30 +203,30 @@ skaldctl create-hall -hall city-watch -unrestricted-tokens
|
||||
|
||||
For more advanced configuration, `skaldctl create-hall` can be invoked
|
||||
with the `-json` flag, in which case it takes a JSON template from standard
|
||||
input. The syntax of a JSON template is just like that of a group
|
||||
input. The syntax of a JSON template is just like that of a hall
|
||||
definition file (see below), except that it must not contain the fields
|
||||
`users` and `wildcard-user`. For example, in order to create a redirect
|
||||
(see the section *Group description reference* below):
|
||||
(see the section *Hall description reference* below):
|
||||
|
||||
```sh
|
||||
echo '{"redirect": "https://skald.example.org:8443/hall/city-watch/"}' | skaldctl create-hall -hall amcw -json
|
||||
```
|
||||
|
||||
Groups are modified using `skaldctl update-hall`:
|
||||
Halls are modified using `skaldctl update-hall`:
|
||||
|
||||
```sh
|
||||
skaldctl update-hall -hall city-watch -unrestricted-tokens=false
|
||||
```
|
||||
|
||||
If a JSON template is provided to `skaldctl update-hall`, then it is
|
||||
merged with the existing group configuration. Entries may be deleted
|
||||
merged with the existing hall configuration. Entries may be deleted
|
||||
by setting them to `null` in the template:
|
||||
|
||||
```sh
|
||||
echo '{"redirect": null}' | skaldctl update-hall -hall amcw
|
||||
```
|
||||
|
||||
A group is deleted using `skaldctl delete-hall`:
|
||||
A hall is deleted using `skaldctl delete-hall`:
|
||||
|
||||
```sh
|
||||
skaldctl delete-hall -hall amcw
|
||||
@@ -266,7 +266,7 @@ skaldctl create-user -hall city-watch -wildcard
|
||||
skaldctl set-password -hall city-watch -wildcard
|
||||
```
|
||||
|
||||
For open groups, where any user can login with any password, the wildcard
|
||||
For open halls, where any user can login with any password, the wildcard
|
||||
user's password is set to the password of type `wildcard`:
|
||||
|
||||
```sh
|
||||
@@ -278,17 +278,17 @@ password types.
|
||||
|
||||
#### Automatic subgroups
|
||||
|
||||
It is sometimes necessary to create a large number of identical groups.
|
||||
It is sometimes necessary to create a large number of identical halls.
|
||||
For example, the author has been using Skald to supervise computer
|
||||
science practicals, where up to 40 students are working in groups of two.
|
||||
science practicals, where up to 40 students are working in pairs.
|
||||
|
||||
While it is possible to automate the creation of groups by accessing
|
||||
While it is possible to automate the creation of halls by accessing
|
||||
Skald's API, by scripting calls to skaldctl, or by generating files
|
||||
directly under `groups/`, Skald provides a facility called *automatic
|
||||
subgroups* that can be used to generate groups on demand.
|
||||
directly under `halls/`, Skald provides a facility called *automatic
|
||||
subgroups* that can be used to generate halls on demand.
|
||||
|
||||
Automatic subgroups are enabled by setting the `"auto-subgroups"`
|
||||
field in the group description:
|
||||
field in the hall description:
|
||||
|
||||
```sh
|
||||
skaldctl create-hall unseen-university -auto-subgroups
|
||||
@@ -297,7 +297,7 @@ skaldctl create-hall unseen-university -auto-subgroups
|
||||
Whenever a user attempts to access a subgroup of `unseen-university`, for
|
||||
example `unseen-university/hex`, the group is created in memory and
|
||||
persists until it is empty and its chat history has expired. The main
|
||||
group's operator can view the list of populated subgroups with the command
|
||||
hall's operator can view the list of populated subgroups with the command
|
||||
`/subgroups`.
|
||||
|
||||
#### Managing tokens
|
||||
@@ -313,26 +313,26 @@ skaldctl list-tokens -l -hall city-watch
|
||||
```
|
||||
|
||||
A token that is generated with the `-include-subgroups` flag applies to
|
||||
the whole hierarchy rooted at the given group, including both ordinary
|
||||
groups and automatically generated subgroups.
|
||||
the whole hierarchy rooted at the given hall, including both ordinary
|
||||
halls and automatically generated subgroups.
|
||||
|
||||
```sh
|
||||
skaldctl create-token -hall city-watch -include-subgroups
|
||||
```
|
||||
|
||||
Such a token can be attached to the root of the group hierarchy, and
|
||||
therefore be valid for any group on the server:
|
||||
Such a token can be attached to the root of the hall hierarchy, and
|
||||
therefore be valid for any hall on the server:
|
||||
|
||||
```sh
|
||||
skaldctl create-token -hall '' -include-subgroups
|
||||
```
|
||||
|
||||
### Group description reference
|
||||
### Hall description reference
|
||||
|
||||
The definition for the group called *hallname* is in the file
|
||||
`groups/hallname.json`; it does not contain the group name, which makes
|
||||
The definition for the hall called *hallname* is in the file
|
||||
`halls/hallname.json`; it does not contain the hall name, which makes
|
||||
it easy to copy or link hall definitions. You may use subdirectories:
|
||||
a file `groups/teaching/networking.json` defines a group called
|
||||
a file `halls/teaching/networking.json` defines a hall called
|
||||
*teaching/networking*.
|
||||
|
||||
Every hall definition file contains a single JSON dictionary. All fields
|
||||
@@ -479,7 +479,7 @@ allows any username with any password.
|
||||
### Hashed passwords
|
||||
|
||||
For security reasons, passwords are usually hashed before being stored in
|
||||
group descriptions (in fact, the `skaldctl` utility does not even support
|
||||
hall descriptions (in fact, the `skaldctl` utility does not even support
|
||||
storing plaintext passwords). A hashed password is represented as a JSON
|
||||
dictionary with a field `type` and a number of type-specific fields.
|
||||
|
||||
@@ -501,7 +501,7 @@ A user entry with a hashed password looks like this:
|
||||
```
|
||||
|
||||
Hashed passwords are normally generated transparently to the user by the
|
||||
`skaldctl set-password` command. When editing group description files
|
||||
`skaldctl set-password` command. When editing hall description files
|
||||
manually, hashed passwords can be generated with the `skaldctl hash-password`
|
||||
utility.
|
||||
|
||||
|
||||
+15
-15
@@ -26,7 +26,7 @@ import (
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
"golang.org/x/term"
|
||||
|
||||
"git.stormux.org/storm/skald/group"
|
||||
"git.stormux.org/storm/skald/hall"
|
||||
"git.stormux.org/storm/skald/token"
|
||||
)
|
||||
|
||||
@@ -229,11 +229,11 @@ func readConfig(filename string) (configuration, error) {
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func makePassword(pw string, algorithm string, iterations, length, saltlen, cost int) (group.Password, error) {
|
||||
func makePassword(pw string, algorithm string, iterations, length, saltlen, cost int) (hall.Password, error) {
|
||||
salt := make([]byte, saltlen)
|
||||
_, err := rand.Read(salt)
|
||||
if err != nil {
|
||||
return group.Password{}, err
|
||||
return hall.Password{}, err
|
||||
}
|
||||
|
||||
switch algorithm {
|
||||
@@ -242,7 +242,7 @@ func makePassword(pw string, algorithm string, iterations, length, saltlen, cost
|
||||
[]byte(pw), salt, iterations, length, sha256.New,
|
||||
)
|
||||
encoded := hex.EncodeToString(key)
|
||||
return group.Password{
|
||||
return hall.Password{
|
||||
Type: "pbkdf2",
|
||||
Hash: "sha-256",
|
||||
Key: &encoded,
|
||||
@@ -254,11 +254,11 @@ func makePassword(pw string, algorithm string, iterations, length, saltlen, cost
|
||||
[]byte(pw), cost,
|
||||
)
|
||||
if err != nil {
|
||||
return group.Password{}, err
|
||||
return hall.Password{}, err
|
||||
}
|
||||
|
||||
k := string(key)
|
||||
return group.Password{
|
||||
return hall.Password{
|
||||
Type: "bcrypt",
|
||||
Key: &k,
|
||||
}, nil
|
||||
@@ -269,11 +269,11 @@ func makePassword(pw string, algorithm string, iterations, length, saltlen, cost
|
||||
"must be the empty string",
|
||||
)
|
||||
}
|
||||
return group.Password{
|
||||
return hall.Password{
|
||||
Type: "wildcard",
|
||||
}, nil
|
||||
default:
|
||||
return group.Password{}, errors.New("unknown password type")
|
||||
return hall.Password{}, errors.New("unknown password type")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,18 +392,18 @@ func initialSetupCmd(cmdname string, args []string) {
|
||||
defer skaldConfig.Close()
|
||||
defer skaldctlConfig.Close()
|
||||
|
||||
var users map[string]group.UserDescription
|
||||
var users map[string]hall.UserDescription
|
||||
if adminPassword != "" {
|
||||
pw, err := makePassword(adminPassword, "bcrypt", 0, 0, 0, 12)
|
||||
if err != nil {
|
||||
log.Fatalf("makePassword: %v", err)
|
||||
}
|
||||
|
||||
perms, err := group.NewPermissions("admin")
|
||||
perms, err := hall.NewPermissions("admin")
|
||||
if err != nil {
|
||||
log.Fatalf("NewPermissions: %v", err)
|
||||
}
|
||||
users = map[string]group.UserDescription{
|
||||
users = map[string]hall.UserDescription{
|
||||
adminUsername: {
|
||||
Password: pw,
|
||||
Permissions: perms,
|
||||
@@ -411,7 +411,7 @@ func initialSetupCmd(cmdname string, args []string) {
|
||||
}
|
||||
}
|
||||
|
||||
config := group.Configuration{
|
||||
config := hall.Configuration{
|
||||
WritableGroups: true,
|
||||
Users: users,
|
||||
}
|
||||
@@ -963,7 +963,7 @@ func parsePermissions(p string, expand bool) (any, error) {
|
||||
if !expand {
|
||||
return p, nil
|
||||
}
|
||||
pp, err := group.NewPermissions(p)
|
||||
pp, err := hall.NewPermissions(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -985,7 +985,7 @@ func formatRawPermissions(permissions []string) string {
|
||||
return fmt.Sprintf("[%s]", perms)
|
||||
}
|
||||
|
||||
func formatPermissions(permissions group.Permissions) string {
|
||||
func formatPermissions(permissions hall.Permissions) string {
|
||||
s := permissions.String()
|
||||
if len(s) > 0 && s[0] != '[' {
|
||||
return s
|
||||
@@ -1056,7 +1056,7 @@ func listUsersCmd(cmdname string, args []string) {
|
||||
fmt.Printf("%-12s (ERROR=%v)\n", user, err)
|
||||
continue
|
||||
}
|
||||
var d group.UserDescription
|
||||
var d hall.UserDescription
|
||||
_, err = getJSON(uu, &d)
|
||||
if err != nil {
|
||||
fmt.Printf("%-12s (ERROR=%v)\n", user, err)
|
||||
|
||||
@@ -4,11 +4,11 @@ import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"git.stormux.org/storm/skald/group"
|
||||
"git.stormux.org/storm/skald/hall"
|
||||
)
|
||||
|
||||
func TestMakePassword(t *testing.T) {
|
||||
doit := func(pw group.Password) {
|
||||
doit := func(pw hall.Password) {
|
||||
ok, _ := pw.Match("secret")
|
||||
if !ok {
|
||||
t.Errorf("%v didn't match", pw)
|
||||
@@ -50,7 +50,7 @@ func TestFormatPermissions(t *testing.T) {
|
||||
{`[]`, "[]", "[]"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
var p group.Permissions
|
||||
var p hall.Permissions
|
||||
err := json.Unmarshal([]byte(test.j), &p)
|
||||
if err != nil {
|
||||
t.Errorf("Unmarshal %#v: %v", test.j, err)
|
||||
|
||||
+1
-1
@@ -4712,7 +4712,7 @@ async function start() {
|
||||
if(groupStatus.name) {
|
||||
group = groupStatus.name;
|
||||
} else {
|
||||
console.warn("no group name in status");
|
||||
console.warn("no hall name in status");
|
||||
group = decodeURIComponent(
|
||||
location.pathname.replace(/^\/[a-z]*\//, '').replace(/\/$/, ''),
|
||||
);
|
||||
|
||||
+3
-3
@@ -5,7 +5,7 @@ import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"git.stormux.org/storm/skald/group"
|
||||
"git.stormux.org/storm/skald/hall"
|
||||
)
|
||||
|
||||
type GroupStats struct {
|
||||
@@ -59,11 +59,11 @@ type Track struct {
|
||||
}
|
||||
|
||||
func GetGroups() []GroupStats {
|
||||
names := group.GetNames()
|
||||
names := hall.GetNames()
|
||||
|
||||
gs := make([]GroupStats, 0, len(names))
|
||||
for _, name := range names {
|
||||
g := group.Get(name)
|
||||
g := hall.Get(name)
|
||||
if g == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -62,13 +62,13 @@ X Search for remaining Galene names and classify each survivor as attribution/hi
|
||||
# PHASE 2: HALL TERMINOLOGY AND DATA MODEL
|
||||
# ============================================================================
|
||||
|
||||
- Rename Go package group/ to hall/ if the package-wide rename stays tractable
|
||||
- Rename package declarations, types, variables, funcs, tests, and comments from group to hall
|
||||
- Rename Group type to Hall and update all compile errors intentionally
|
||||
- Rename group description files/concepts to hall description files/concepts
|
||||
- Rename default directory flag: -groups -> -halls
|
||||
- Rename default data directory: groups/ -> halls/
|
||||
- Rename public listing concept from public groups to public halls
|
||||
X Rename Go package group/ to hall/ if the package-wide rename stays tractable
|
||||
X Rename package declarations, types, variables, funcs, tests, and comments from group to hall
|
||||
X Rename Group type to Hall and update all compile errors intentionally
|
||||
X Rename group description files/concepts to hall description files/concepts
|
||||
X Rename default directory flag: -groups -> -halls
|
||||
X Rename default data directory: groups/ -> halls/
|
||||
X Rename public listing concept from public groups to public halls
|
||||
- Rename subgroups to subhalls everywhere, including JSON fields and commands
|
||||
- Rename auto-subgroups -> auto-subhalls
|
||||
- Rename allow-subgroups -> allow-subhalls
|
||||
|
||||
+24
-24
@@ -13,7 +13,7 @@ import (
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"git.stormux.org/storm/skald/group"
|
||||
"git.stormux.org/storm/skald/hall"
|
||||
"git.stormux.org/storm/skald/stats"
|
||||
"git.stormux.org/storm/skald/token"
|
||||
)
|
||||
@@ -47,7 +47,7 @@ func checkPasswordAdmin(w http.ResponseWriter, r *http.Request, hallname, user s
|
||||
}
|
||||
}
|
||||
if ok && !wildcard && username == user {
|
||||
desc, err := group.GetDescription(hallname)
|
||||
desc, err := hall.GetDescription(hallname)
|
||||
if err != nil {
|
||||
internalError(w,
|
||||
"Get description for group %v: %v",
|
||||
@@ -193,7 +193,7 @@ func apiGroupHandler(w http.ResponseWriter, r *http.Request, pth string) {
|
||||
methodNotAllowed(w, "HEAD, GET")
|
||||
return
|
||||
}
|
||||
groups, err := group.GetDescriptionNames()
|
||||
groups, err := hall.GetDescriptionNames()
|
||||
if err != nil {
|
||||
httpError(w, err)
|
||||
return
|
||||
@@ -233,7 +233,7 @@ func apiGroupHandler(w http.ResponseWriter, r *http.Request, pth string) {
|
||||
}
|
||||
|
||||
if r.Method == "HEAD" || r.Method == "GET" {
|
||||
desc, etag, err := group.GetSanitisedDescription(g)
|
||||
desc, etag, err := hall.GetSanitisedDescription(g)
|
||||
if err != nil {
|
||||
httpError(w, err)
|
||||
return
|
||||
@@ -249,7 +249,7 @@ func apiGroupHandler(w http.ResponseWriter, r *http.Request, pth string) {
|
||||
sendJSON(w, r, desc)
|
||||
return
|
||||
} else if r.Method == "PUT" {
|
||||
etag, err := group.GetDescriptionTag(g)
|
||||
etag, err := hall.GetDescriptionTag(g)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
err = nil
|
||||
etag = ""
|
||||
@@ -263,12 +263,12 @@ func apiGroupHandler(w http.ResponseWriter, r *http.Request, pth string) {
|
||||
return
|
||||
}
|
||||
|
||||
var newdesc group.Description
|
||||
var newdesc hall.Description
|
||||
done = getJSON(w, r, &newdesc)
|
||||
if done {
|
||||
return
|
||||
}
|
||||
err = group.UpdateDescription(g, etag, &newdesc)
|
||||
err = hall.UpdateDescription(g, etag, &newdesc)
|
||||
if err != nil {
|
||||
httpError(w, err)
|
||||
return
|
||||
@@ -280,7 +280,7 @@ func apiGroupHandler(w http.ResponseWriter, r *http.Request, pth string) {
|
||||
}
|
||||
return
|
||||
} else if r.Method == "DELETE" {
|
||||
etag, err := group.GetDescriptionTag(g)
|
||||
etag, err := hall.GetDescriptionTag(g)
|
||||
if err != nil {
|
||||
httpError(w, err)
|
||||
return
|
||||
@@ -290,7 +290,7 @@ func apiGroupHandler(w http.ResponseWriter, r *http.Request, pth string) {
|
||||
if done {
|
||||
return
|
||||
}
|
||||
err = group.DeleteDescription(g, etag)
|
||||
err = hall.DeleteDescription(g, etag)
|
||||
if err != nil {
|
||||
httpError(w, err)
|
||||
return
|
||||
@@ -318,7 +318,7 @@ func usersHandler(w http.ResponseWriter, r *http.Request, g, pth string) {
|
||||
methodNotAllowed(w, "HEAD, GET")
|
||||
return
|
||||
}
|
||||
users, etag, err := group.GetUsers(g)
|
||||
users, etag, err := hall.GetUsers(g)
|
||||
if err != nil {
|
||||
httpError(w, err)
|
||||
return
|
||||
@@ -371,7 +371,7 @@ func userHandler(w http.ResponseWriter, r *http.Request, g, user string, wildcar
|
||||
}
|
||||
|
||||
if r.Method == "HEAD" || r.Method == "GET" {
|
||||
user, etag, err := group.GetSanitisedUser(g, user, wildcard)
|
||||
user, etag, err := hall.GetSanitisedUser(g, user, wildcard)
|
||||
if err != nil {
|
||||
httpError(w, err)
|
||||
return
|
||||
@@ -384,7 +384,7 @@ func userHandler(w http.ResponseWriter, r *http.Request, g, user string, wildcar
|
||||
sendJSON(w, r, user)
|
||||
return
|
||||
} else if r.Method == "PUT" {
|
||||
etag, err := group.GetUserTag(g, user, wildcard)
|
||||
etag, err := hall.GetUserTag(g, user, wildcard)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
etag = ""
|
||||
err = nil
|
||||
@@ -398,12 +398,12 @@ func userHandler(w http.ResponseWriter, r *http.Request, g, user string, wildcar
|
||||
return
|
||||
}
|
||||
|
||||
var newdesc group.UserDescription
|
||||
var newdesc hall.UserDescription
|
||||
done = getJSON(w, r, &newdesc)
|
||||
if done {
|
||||
return
|
||||
}
|
||||
err = group.UpdateUser(g, user, wildcard, etag, &newdesc)
|
||||
err = hall.UpdateUser(g, user, wildcard, etag, &newdesc)
|
||||
if err != nil {
|
||||
httpError(w, err)
|
||||
return
|
||||
@@ -415,7 +415,7 @@ func userHandler(w http.ResponseWriter, r *http.Request, g, user string, wildcar
|
||||
}
|
||||
return
|
||||
} else if r.Method == "DELETE" {
|
||||
etag, err := group.GetUserTag(g, user, wildcard)
|
||||
etag, err := hall.GetUserTag(g, user, wildcard)
|
||||
if err != nil {
|
||||
httpError(w, err)
|
||||
return
|
||||
@@ -426,7 +426,7 @@ func userHandler(w http.ResponseWriter, r *http.Request, g, user string, wildcar
|
||||
return
|
||||
}
|
||||
|
||||
err = group.DeleteUser(g, user, wildcard, etag)
|
||||
err = hall.DeleteUser(g, user, wildcard, etag)
|
||||
if err != nil {
|
||||
httpError(w, err)
|
||||
return
|
||||
@@ -447,12 +447,12 @@ func passwordHandler(w http.ResponseWriter, r *http.Request, g, user string, wil
|
||||
}
|
||||
|
||||
if r.Method == "PUT" {
|
||||
var pw group.Password
|
||||
var pw hall.Password
|
||||
done := getJSON(w, r, &pw)
|
||||
if done {
|
||||
return
|
||||
}
|
||||
err := group.SetUserPassword(g, user, wildcard, pw)
|
||||
err := hall.SetUserPassword(g, user, wildcard, pw)
|
||||
if err != nil {
|
||||
httpError(w, err)
|
||||
return
|
||||
@@ -471,11 +471,11 @@ func passwordHandler(w http.ResponseWriter, r *http.Request, g, user string, wil
|
||||
}
|
||||
|
||||
k := string(key)
|
||||
pw := group.Password{
|
||||
pw := hall.Password{
|
||||
Type: "bcrypt",
|
||||
Key: &k,
|
||||
}
|
||||
err = group.SetUserPassword(g, user, wildcard, pw)
|
||||
err = hall.SetUserPassword(g, user, wildcard, pw)
|
||||
if err != nil {
|
||||
httpError(w, err)
|
||||
return
|
||||
@@ -483,7 +483,7 @@ func passwordHandler(w http.ResponseWriter, r *http.Request, g, user string, wil
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
} else if r.Method == "DELETE" {
|
||||
err := group.SetUserPassword(g, user, wildcard, group.Password{})
|
||||
err := hall.SetUserPassword(g, user, wildcard, hall.Password{})
|
||||
if err != nil {
|
||||
httpError(w, err)
|
||||
return
|
||||
@@ -528,7 +528,7 @@ func keysHandler(w http.ResponseWriter, r *http.Request, g string) {
|
||||
httpError(w, err)
|
||||
return
|
||||
}
|
||||
err = group.SetKeys(g, keys.Keys)
|
||||
err = hall.SetKeys(g, keys.Keys)
|
||||
if err != nil {
|
||||
httpError(w, err)
|
||||
return
|
||||
@@ -536,7 +536,7 @@ func keysHandler(w http.ResponseWriter, r *http.Request, g string) {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
} else if r.Method == "DELETE" {
|
||||
err := group.SetKeys(g, nil)
|
||||
err := hall.SetKeys(g, nil)
|
||||
if err != nil {
|
||||
httpError(w, err)
|
||||
return
|
||||
@@ -563,7 +563,7 @@ func tokensHandler(w http.ResponseWriter, r *http.Request, g, pth string) {
|
||||
|
||||
if g != "" {
|
||||
// check that the group exists
|
||||
_, err := group.GetDescription(g)
|
||||
_, err := hall.GetDescription(g)
|
||||
if err != nil {
|
||||
httpError(w, err)
|
||||
return
|
||||
|
||||
+12
-12
@@ -15,7 +15,7 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"git.stormux.org/storm/skald/group"
|
||||
"git.stormux.org/storm/skald/hall"
|
||||
"git.stormux.org/storm/skald/token"
|
||||
)
|
||||
|
||||
@@ -34,8 +34,8 @@ func setup() {
|
||||
func setupTest(dir, datadir string) error {
|
||||
setup()
|
||||
|
||||
group.Directory = dir
|
||||
group.DataDirectory = datadir
|
||||
hall.Directory = dir
|
||||
hall.DataDirectory = datadir
|
||||
config := `{
|
||||
"writableGroups": true,
|
||||
"users": {
|
||||
@@ -45,7 +45,7 @@ func setupTest(dir, datadir string) error {
|
||||
}
|
||||
}
|
||||
}`
|
||||
f, err := os.Create(filepath.Join(group.DataDirectory, "config.json"))
|
||||
f, err := os.Create(filepath.Join(hall.DataDirectory, "config.json"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -142,7 +142,7 @@ func TestApi(t *testing.T) {
|
||||
t.Errorf("Create hall: %v %v", err, resp.StatusCode)
|
||||
}
|
||||
|
||||
var desc *group.Description
|
||||
var desc *hall.Description
|
||||
err = getJSON("/skald-api/v0/.halls/test/", &desc)
|
||||
if err != nil || len(desc.Users) != 0 {
|
||||
t.Errorf("Get hall: %v", err)
|
||||
@@ -223,7 +223,7 @@ func TestApi(t *testing.T) {
|
||||
t.Errorf("Set password (POST): %v %v", err, resp.StatusCode)
|
||||
}
|
||||
|
||||
var user group.UserDescription
|
||||
var user hall.UserDescription
|
||||
err = getJSON("/skald-api/v0/.halls/test/.users/jch", &user)
|
||||
if err != nil {
|
||||
t.Errorf("Get user: %v", err)
|
||||
@@ -232,7 +232,7 @@ func TestApi(t *testing.T) {
|
||||
t.Errorf("User not sanitised properly")
|
||||
}
|
||||
|
||||
desc, err = group.GetDescription("test")
|
||||
desc, err = hall.GetDescription("test")
|
||||
if err != nil {
|
||||
t.Errorf("GetDescription: %v", err)
|
||||
}
|
||||
@@ -251,7 +251,7 @@ func TestApi(t *testing.T) {
|
||||
t.Errorf("Delete hall: %v %v", err, resp.StatusCode)
|
||||
}
|
||||
|
||||
desc, err = group.GetDescription("test")
|
||||
desc, err = hall.GetDescription("test")
|
||||
if err != nil {
|
||||
t.Errorf("GetDescription: %v", err)
|
||||
}
|
||||
@@ -272,7 +272,7 @@ func TestApi(t *testing.T) {
|
||||
t.Errorf("Get wildcard user: %v", err)
|
||||
}
|
||||
|
||||
desc, err = group.GetDescription("test")
|
||||
desc, err = hall.GetDescription("test")
|
||||
if err != nil {
|
||||
t.Errorf("GetDescription: %v", err)
|
||||
}
|
||||
@@ -287,7 +287,7 @@ func TestApi(t *testing.T) {
|
||||
t.Errorf("Delete wildcard user: %v %v", err, resp.StatusCode)
|
||||
}
|
||||
|
||||
desc, err = group.GetDescription("test")
|
||||
desc, err = hall.GetDescription("test")
|
||||
if err != nil {
|
||||
t.Errorf("GetDescription: %v", err)
|
||||
}
|
||||
@@ -414,7 +414,7 @@ func TestApi(t *testing.T) {
|
||||
t.Errorf("Delete hall: %v %v", err, resp.StatusCode)
|
||||
}
|
||||
|
||||
_, err = group.GetDescription("test")
|
||||
_, err = hall.GetDescription("test")
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
t.Errorf("Group exists after delete")
|
||||
}
|
||||
@@ -451,7 +451,7 @@ func TestApiBadAuth(t *testing.T) {
|
||||
do("GET", "/skald-api/v0/.halls/")
|
||||
do("PUT", "/skald-api/v0/.halls/test/")
|
||||
|
||||
f, err := os.Create(filepath.Join(group.Directory, "test.json"))
|
||||
f, err := os.Create(filepath.Join(hall.Directory, "test.json"))
|
||||
if err != nil {
|
||||
t.Fatalf("Create(test.json): %v", err)
|
||||
}
|
||||
|
||||
+22
-22
@@ -22,7 +22,7 @@ import (
|
||||
"github.com/gorilla/websocket"
|
||||
|
||||
"git.stormux.org/storm/skald/diskwriter"
|
||||
"git.stormux.org/storm/skald/group"
|
||||
"git.stormux.org/storm/skald/hall"
|
||||
"git.stormux.org/storm/skald/rtpconn"
|
||||
"github.com/jech/cert"
|
||||
)
|
||||
@@ -64,7 +64,7 @@ func Serve(address string, dataDir string) error {
|
||||
}
|
||||
}
|
||||
s.RegisterOnShutdown(func() {
|
||||
group.Shutdown("server is shutting down")
|
||||
hall.Shutdown("server is shutting down")
|
||||
})
|
||||
|
||||
server = s
|
||||
@@ -130,11 +130,11 @@ func httpError(w http.ResponseWriter, err error) {
|
||||
notFound(w)
|
||||
return
|
||||
}
|
||||
if errors.Is(err, group.ErrUnknownPermission) {
|
||||
if errors.Is(err, hall.ErrUnknownPermission) {
|
||||
http.Error(w, "unknown permission", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
var autherr *group.NotAuthorisedError
|
||||
var autherr *hall.NotAuthorisedError
|
||||
if errors.As(err, &autherr) {
|
||||
log.Printf("HTTP server error: %v", err)
|
||||
http.Error(w, "not authorised", http.StatusUnauthorized)
|
||||
@@ -160,7 +160,7 @@ const (
|
||||
)
|
||||
|
||||
func redirect(w http.ResponseWriter, r *http.Request) bool {
|
||||
conf, err := group.GetConfiguration()
|
||||
conf, err := hall.GetConfiguration()
|
||||
if err != nil || conf.CanonicalHost == "" {
|
||||
return false
|
||||
}
|
||||
@@ -285,7 +285,7 @@ func serveFile(w http.ResponseWriter, r *http.Request, p string) {
|
||||
http.ServeContent(w, r, fi.Name(), fi.ModTime(), f)
|
||||
}
|
||||
|
||||
func parseGroupName(prefix string, p string) string {
|
||||
func parseHallName(prefix string, p string) string {
|
||||
if !strings.HasPrefix(p, prefix) {
|
||||
return ""
|
||||
}
|
||||
@@ -346,13 +346,13 @@ func groupHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
name := parseGroupName("/hall/", r.URL.Path)
|
||||
name := parseHallName("/hall/", r.URL.Path)
|
||||
if name == "" {
|
||||
notFound(w)
|
||||
return
|
||||
}
|
||||
|
||||
g, err := group.Add(name, nil)
|
||||
g, err := hall.Add(name, nil)
|
||||
if err != nil {
|
||||
httpError(w, err)
|
||||
return
|
||||
@@ -375,7 +375,7 @@ func groupHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func baseURL(r *http.Request) (*url.URL, error) {
|
||||
conf, err := group.GetConfiguration()
|
||||
conf, err := hall.GetConfiguration()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -415,13 +415,13 @@ func groupStatusHandler(w http.ResponseWriter, r *http.Request) {
|
||||
internalError(w, "groupStatusHandler: this shouldn't happen")
|
||||
return
|
||||
}
|
||||
name := parseGroupName("/hall/", pth)
|
||||
name := parseHallName("/hall/", pth)
|
||||
if name == "" {
|
||||
notFound(w)
|
||||
return
|
||||
}
|
||||
|
||||
g, err := group.Add(name, nil)
|
||||
g, err := hall.Add(name, nil)
|
||||
if err != nil {
|
||||
httpError(w, err)
|
||||
return
|
||||
@@ -458,13 +458,13 @@ func publicHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
g := group.GetPublic(base)
|
||||
g := hall.GetPublic(base)
|
||||
e := json.NewEncoder(w)
|
||||
e.Encode(g)
|
||||
}
|
||||
|
||||
func adminMatch(username, password string) (bool, error) {
|
||||
conf, err := group.GetConfiguration()
|
||||
conf, err := hall.GetConfiguration()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -512,7 +512,7 @@ func CheckOrigin(w http.ResponseWriter, r *http.Request, admin bool) bool {
|
||||
if err == nil && strings.EqualFold(o.Host, r.Host) {
|
||||
ok = true
|
||||
} else {
|
||||
conf, err := group.GetConfiguration()
|
||||
conf, err := hall.GetConfiguration()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@@ -613,20 +613,20 @@ func recordingsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
for len(p) > 0 && p[len(p)-1] == '/' {
|
||||
p = p[:len(p)-1]
|
||||
}
|
||||
group = parseGroupName("/", p)
|
||||
group = parseHallName("/", p)
|
||||
if group == "" {
|
||||
http.Error(w, "Bad group name", http.StatusBadRequest)
|
||||
http.Error(w, "Bad hall name", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if p[len(p)-1] == '/' {
|
||||
http.Error(w, "Bad group name", http.StatusBadRequest)
|
||||
http.Error(w, "Bad hall name", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
group, filename = path.Split(p)
|
||||
group = parseGroupName("/", group)
|
||||
group = parseHallName("/", group)
|
||||
if group == "" {
|
||||
http.Error(w, "Bad group name", http.StatusBadRequest)
|
||||
http.Error(w, "Bad hall name", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -711,13 +711,13 @@ func checkGroupPermissions(w http.ResponseWriter, r *http.Request, hallname stri
|
||||
return false
|
||||
}
|
||||
|
||||
g := group.Get(hallname)
|
||||
g := hall.Get(hallname)
|
||||
if g == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
_, p, err := g.GetPermission(
|
||||
group.ClientCredentials{
|
||||
hall.ClientCredentials{
|
||||
Username: &user,
|
||||
Password: pass,
|
||||
},
|
||||
@@ -732,7 +732,7 @@ func checkGroupPermissions(w http.ResponseWriter, r *http.Request, hallname stri
|
||||
}
|
||||
}
|
||||
if err != nil || !record {
|
||||
var autherr *group.NotAuthorisedError
|
||||
var autherr *hall.NotAuthorisedError
|
||||
if errors.As(err, &autherr) {
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
|
||||
@@ -10,10 +10,10 @@ import (
|
||||
|
||||
"github.com/pion/webrtc/v4"
|
||||
|
||||
"git.stormux.org/storm/skald/group"
|
||||
"git.stormux.org/storm/skald/hall"
|
||||
)
|
||||
|
||||
func TestParseGroupName(t *testing.T) {
|
||||
func TestParseHallName(t *testing.T) {
|
||||
a := []struct{ p, g string }{
|
||||
{"", ""},
|
||||
{"/foo", ""},
|
||||
@@ -29,7 +29,7 @@ func TestParseGroupName(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, pg := range a {
|
||||
g := parseGroupName("/hall/", pg.p)
|
||||
g := parseHallName("/hall/", pg.p)
|
||||
if g != pg.g {
|
||||
t.Errorf("Path %v, got %v, expected %v",
|
||||
pg.p, g, pg.g)
|
||||
@@ -58,10 +58,10 @@ func TestBase(t *testing.T) {
|
||||
}
|
||||
|
||||
dir := t.TempDir()
|
||||
group.DataDirectory = dir
|
||||
hall.DataDirectory = dir
|
||||
|
||||
for _, v := range a {
|
||||
conf := group.Configuration{
|
||||
conf := hall.Configuration{
|
||||
ProxyURL: v.p,
|
||||
}
|
||||
c, err := json.Marshal(conf)
|
||||
@@ -200,7 +200,7 @@ func TestFormatICEServer(t *testing.T) {
|
||||
|
||||
func TestMatchAdmin(t *testing.T) {
|
||||
d := t.TempDir()
|
||||
group.DataDirectory = d
|
||||
hall.DataDirectory = d
|
||||
|
||||
filename := filepath.Join(d, "config.json")
|
||||
f, err := os.Create(filename)
|
||||
|
||||
+10
-10
@@ -17,7 +17,7 @@ import (
|
||||
|
||||
"github.com/pion/webrtc/v4"
|
||||
|
||||
"git.stormux.org/storm/skald/group"
|
||||
"git.stormux.org/storm/skald/hall"
|
||||
"git.stormux.org/storm/skald/ice"
|
||||
"git.stormux.org/storm/skald/rtpconn"
|
||||
"git.stormux.org/storm/skald/sdpfrag"
|
||||
@@ -153,13 +153,13 @@ func whipEndpointHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
name := parseGroupName("/hall/", pth)
|
||||
name := parseHallName("/hall/", pth)
|
||||
if name == "" {
|
||||
notFound(w)
|
||||
return
|
||||
}
|
||||
|
||||
g, err := group.Add(name, nil)
|
||||
g, err := hall.Add(name, nil)
|
||||
if err != nil {
|
||||
httpError(w, err)
|
||||
return
|
||||
@@ -199,7 +199,7 @@ func whipEndpointHandler(w http.ResponseWriter, r *http.Request) {
|
||||
token := parseBearerToken(r.Header.Get("Authorization"))
|
||||
|
||||
whip := "whip"
|
||||
creds := group.ClientCredentials{
|
||||
creds := hall.ClientCredentials{
|
||||
Username: &whip,
|
||||
Token: token,
|
||||
}
|
||||
@@ -221,7 +221,7 @@ func whipEndpointHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
c := rtpconn.NewWhipClient(g, id, token, addr)
|
||||
|
||||
_, err = group.AddClient(g.Name(), c, creds)
|
||||
_, err = hall.AddClient(g.Name(), c, creds)
|
||||
if err != nil {
|
||||
log.Printf("WHIP: %v", err)
|
||||
httpError(w, err)
|
||||
@@ -229,7 +229,7 @@ func whipEndpointHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if !canPresent(c.Permissions()) {
|
||||
group.DelClient(c)
|
||||
hall.DelClient(c)
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
@@ -238,7 +238,7 @@ func whipEndpointHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
answer, err := c.NewConnection(r.Context(), body)
|
||||
if err != nil {
|
||||
group.DelClient(c)
|
||||
hall.DelClient(c)
|
||||
log.Printf("WHIP offer: %v", err)
|
||||
httpError(w, err)
|
||||
return
|
||||
@@ -269,13 +269,13 @@ func whipResourceHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
name := parseGroupName("/hall/", pth)
|
||||
name := parseHallName("/hall/", pth)
|
||||
if name == "" {
|
||||
notFound(w)
|
||||
return
|
||||
}
|
||||
|
||||
g := group.Get(name)
|
||||
g := hall.Get(name)
|
||||
if g == nil {
|
||||
notFound(w)
|
||||
return
|
||||
@@ -295,7 +295,7 @@ func whipResourceHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if t := c.Token(); t != "" {
|
||||
token := parseBearerToken(r.Header.Get("Authorization"))
|
||||
if !group.ConstantTimeCompare(t, token) {
|
||||
if !hall.ConstantTimeCompare(t, token) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user