lock and unlock should now broadcast to the hall. Users trying to enter if hall is locked should now get message indicating the hall is locked. Removed redundant start with options. Browser requests mic permissions, also there is a mute option in the ui itself, so this seemed superfluous

This commit is contained in:
Storm Dragon
2026-05-22 02:10:50 -04:00
parent 47d13083f9
commit aac197ef54
6 changed files with 111 additions and 23 deletions
@@ -2,7 +2,7 @@
# shellcheck shell=bash disable=SC2034,SC2154
pkgname=skald-git
pkgver=0.0.0.r1526.ga0a1b79
pkgver=0.0.0.r1527.g47d1308
pkgrel=1
pkgdesc='Audio-only hall-based conferencing server'
arch=('x86_64' 'aarch64')
+2 -2
View File
@@ -549,7 +549,7 @@ func AddClient(hall string, c Client, creds ClientCredentials) (*Hall, error) {
if g.locked != nil {
m := *g.locked
if m == "" {
m = "this hall is locked"
m = "Hall is locked."
}
return nil, UserError(m)
}
@@ -632,7 +632,7 @@ func autoLockKick(g *Hall) {
}
}
if g.description.Autolock && g.locked == nil {
m := "this hall is locked"
m := "Hall is locked."
g.locked = &m
for _, c := range clients {
c.Joined(g.Name(), "change")
+79
View File
@@ -4,10 +4,14 @@ import (
"encoding/json"
"errors"
"fmt"
"net"
"os"
"path/filepath"
"sort"
"testing"
"time"
"git.stormux.org/storm/skald/conn"
"github.com/pion/webrtc/v4"
)
@@ -121,6 +125,81 @@ func TestChatHistory(t *testing.T) {
}
}
type testClient struct {
id string
username string
permissions []string
}
func (c *testClient) Hall() *Hall { return nil }
func (c *testClient) Addr() net.Addr { return nil }
func (c *testClient) Id() string { return c.id }
func (c *testClient) Username() string { return c.username }
func (c *testClient) SetUsername(username string) { c.username = username }
func (c *testClient) Permissions() []string { return c.permissions }
func (c *testClient) SetPermissions(permissions []string) { c.permissions = permissions }
func (c *testClient) Data() map[string]interface{} { return nil }
func (c *testClient) PushConn(*Hall, string, conn.Up, []conn.UpTrack, string) error {
return nil
}
func (c *testClient) RequestConns(Client, *Hall, string) error { return nil }
func (c *testClient) Joined(string, string) error { return nil }
func (c *testClient) PushClient(string, string, string, string, []string, map[string]interface{}) error {
return nil
}
func (c *testClient) Kick(string, *string, string) error { return nil }
func TestLockedHallJoinMessage(t *testing.T) {
halls.halls = nil
oldDirectory := Directory
Directory = t.TempDir()
t.Cleanup(func() {
Directory = oldDirectory
halls.halls = nil
})
err := os.WriteFile(
filepath.Join(Directory, "locked-message-test.json"),
[]byte(`{
"users": {
"user1": {"password": "secret", "permissions": "present"},
"admin": {"password": "secret", "permissions": "op"}
}
}`),
0644,
)
if err != nil {
t.Fatalf("WriteFile: %v", err)
}
g, err := Add("locked-message-test", nil)
if err != nil {
t.Fatalf("Add: %v", err)
}
g.SetLocked(true, "")
username := "user1"
_, err = AddClient(g.Name(), &testClient{id: "user1"}, ClientCredentials{
Username: &username,
Password: "secret",
})
if err == nil {
t.Fatalf("AddClient unexpectedly succeeded")
}
if got, want := err.Error(), "Hall is locked."; got != want {
t.Fatalf("locked join message: got %q, want %q", got, want)
}
adminUsername := "admin"
_, err = AddClient(g.Name(), &testClient{id: "admin"}, ClientCredentials{
Username: &adminUsername,
Password: "secret",
})
if err != nil {
t.Fatalf("operator join should bypass lock: %v", err)
}
}
func permissionsEqual(a, b []string) bool {
// nil case
if len(a) == 0 && len(b) == 0 {
+17
View File
@@ -70,6 +70,18 @@ func broadcastRecordingStatus(g *hall.Hall, message string) {
}
}
func broadcastHallInfo(g *hall.Hall, message string) {
err := broadcast(g.GetClients(nil), clientMessage{
Type: "usermessage",
Kind: "info",
Privileged: true,
Value: message,
})
if err != nil {
log.Printf("broadcast(hall info): %v", err)
}
}
type webClient struct {
hall *hall.Hall
addr net.Addr
@@ -1658,6 +1670,11 @@ func handleClientMessage(c *webClient, m clientMessage) error {
message = v
}
g.SetLocked(m.Kind == "lock", message)
if m.Kind == "lock" {
broadcastHallInfo(g, "Hall locked")
} else {
broadcastHallInfo(g, "Hall unlocked")
}
case "record":
if !member("record", c.permissions) {
return c.error(hall.UserError("not authorised"))
-13
View File
@@ -103,19 +103,6 @@
<input id="password" type="password" name="password"
autocomplete="current-password" class="form-control"/>
</div>
<fieldset>
<legend>Enable at start:</legend>
<div class="present-switch">
<p class="switch-radio">
<input id="presentoff" type="radio" name="presentradio" value=""/>
<label for="presentoff">Nothing</label>
</p>
<p class="switch-radio">
<input id="presentmike" type="radio" name="presentradio" value="mike" checked/>
<label for="presentmike">Microphone</label>
</p>
</div>
</fieldset>
<div class="clear"></div>
<div class="connect">
<input id="connectbutton" type="submit" class="btn btn-blue" value="Connect"/>
+12 -7
View File
@@ -2278,8 +2278,7 @@ function gotUserMessage(id, dest, username, time, privileged, kind, error, messa
switch(kind) {
case 'kicked':
case 'error':
case 'warning':
case 'info': {
case 'warning': {
if(!privileged) {
console.error(`Got unprivileged message of kind ${kind}`);
return;
@@ -2288,6 +2287,16 @@ function gotUserMessage(id, dest, username, time, privileged, kind, error, messa
displayError(`${from} said: ${message}`, kind);
break;
}
case 'info': {
if(!privileged) {
console.error(`Got unprivileged message of kind ${kind}`);
return;
}
let text = '' + message;
localMessage(text);
displayMessage(text);
break;
}
case 'recording': {
if(!privileged) {
console.error(`Got unprivileged message of kind ${kind}`);
@@ -3589,11 +3598,7 @@ document.getElementById('loginform').onsubmit = async function(e) {
setVisibility('passwordform', true);
if(getInputElement('presentmike').checked)
presentRequested = 'mike';
else
presentRequested = null;
getInputElement('presentmike').checked = true;
presentRequested = 'mike';
// Connect to the server, gotConnected will join.
serverConnect();