feat: LiveKit migration — permissions, auth hardening, voice improvements

Pre-review snapshot of LiveKit migration changes including:
- Permission computation fix (allow-wins semantics)
- Timing-safe password comparison with dummy hash
- Rate limiter window fix
- Dev credential clearing for LiveKit
- Voice leave/join broadcast improvements
- Migration transaction wrapping
- Chat edit/delete permission guards
- TOTP verification endpoint
- Embed regex injection fix
This commit is contained in:
jevb
2026-03-24 21:30:23 +01:00
parent 3f58345e6c
commit e0437d4d8d
27 changed files with 188 additions and 64 deletions
+9 -1
View File
@@ -10,7 +10,11 @@ import (
func (d *DB) ListChannels() ([]Channel, error) {
rows, err := d.sqlDB.Query(
`SELECT id, name, type, COALESCE(category,''), COALESCE(topic,''),
position, slow_mode, archived, created_at
position, slow_mode, archived, created_at,
COALESCE(voice_max_users, 0),
voice_quality,
mixing_threshold,
COALESCE(voice_max_video, 0)
FROM channels ORDER BY position ASC, id ASC`,
)
if err != nil {
@@ -172,12 +176,16 @@ func (d *DB) GetAllChannelPermissionsForRole(roleID int64) (map[int64]ChannelOve
// ─── helpers ──────────────────────────────────────────────────────────────────
// scanChannel scans a single channel row from *sql.Rows.
// The query must select the 13 columns: id, name, type, category, topic,
// position, slow_mode, archived, created_at, voice_max_users,
// voice_quality, mixing_threshold, voice_max_video.
func scanChannel(rows *sql.Rows) (Channel, error) {
var ch Channel
var archived int
err := rows.Scan(
&ch.ID, &ch.Name, &ch.Type, &ch.Category, &ch.Topic,
&ch.Position, &ch.SlowMode, &archived, &ch.CreatedAt,
&ch.VoiceMaxUsers, &ch.VoiceQuality, &ch.MixingThreshold, &ch.VoiceMaxVideo,
)
if err != nil {
return Channel{}, err
+12 -1
View File
@@ -168,15 +168,26 @@ func MigrateFS(database *DB, fsys fs.FS) error {
continue
}
tx, txErr := database.sqlDB.Begin()
if txErr != nil {
return fmt.Errorf("begin tx for %s: %w", name, txErr)
}
raw, readErr := fs.ReadFile(fsys, name)
if readErr != nil {
tx.Rollback() //nolint:errcheck
return fmt.Errorf("reading migration %s: %w", name, readErr)
}
if _, execErr := database.sqlDB.Exec(string(raw)); execErr != nil {
if _, execErr := tx.Exec(string(raw)); execErr != nil {
tx.Rollback() //nolint:errcheck
return fmt.Errorf("executing migration %s: %w", name, execErr)
}
if commitErr := tx.Commit(); commitErr != nil {
return fmt.Errorf("commit migration %s: %w", name, commitErr)
}
if err := recordApplied(database, name); err != nil {
return err
}