feat: add webhook auth guard and IRC password/username support

Add WEBHOOK_SECRET env var for authenticating incoming Owncast webhooks
via a ?secret= query parameter. Requests with a missing or incorrect
secret are rejected with 401. If unset, all requests are accepted
(with a startup warning).

Also includes previously uncommitted work:
- IRC server password support (IRC_PASSWORD env var, PASS command)
- IRC username/ident field in config
- IRC_PASSWORD and SELinux volume flag in docker-compose.yml

Made-with: Cursor
This commit is contained in:
cottongin
2026-03-13 00:53:59 -04:00
parent 1af9bd1def
commit 78fec2946c
11 changed files with 212 additions and 7 deletions

View File

@@ -21,6 +21,8 @@ pub struct IrcConfig {
pub tls: bool,
#[serde(default = "default_nick")]
pub nick: String,
#[serde(default)]
pub username: Option<String>,
pub channel: String,
}
@@ -60,10 +62,18 @@ impl BridgeConfig {
Ok(config)
}
pub fn irc_server_password() -> Option<String> {
std::env::var("IRC_PASSWORD").ok()
}
pub fn owncast_access_token(&self) -> anyhow::Result<String> {
std::env::var("OWNCAST_ACCESS_TOKEN")
.map_err(|_| anyhow::anyhow!("OWNCAST_ACCESS_TOKEN env var not set"))
}
pub fn webhook_secret() -> Option<String> {
std::env::var("WEBHOOK_SECRET").ok()
}
}
fn default_irc_port() -> u16 { 6667 }
@@ -100,6 +110,7 @@ impl BridgeConfig {
port: 6667,
tls: false,
nick: "test-bot".to_string(),
username: None,
channel: "#test".to_string(),
},
owncast: OwncastConfig {
@@ -134,6 +145,7 @@ url = "https://owncast.example.com"
assert_eq!(config.irc.port, 6667);
assert_eq!(config.irc.tls, false);
assert_eq!(config.irc.nick, "owncast-bridge");
assert!(config.irc.username.is_none());
assert_eq!(config.irc.channel, "#test");
assert_eq!(config.owncast.url, "https://owncast.example.com");
assert_eq!(config.owncast.webhook_port, 9078);
@@ -153,6 +165,7 @@ server = "irc.example.com"
port = 6697
tls = true
nick = "mybot"
username = "myident"
channel = "#mychan"
[owncast]
@@ -173,12 +186,21 @@ socket_path = "/var/run/bridge.sock"
assert_eq!(config.irc.port, 6697);
assert!(config.irc.tls);
assert_eq!(config.irc.nick, "mybot");
assert_eq!(config.irc.username.as_deref(), Some("myident"));
assert_eq!(config.owncast.webhook_port, 8888);
assert!(config.owncast.websocket_enabled);
assert_eq!(config.bridge.message_buffer_size, 50);
assert_eq!(config.control.socket_path, "/var/run/bridge.sock");
}
#[test]
fn test_irc_server_password_from_env() {
std::env::set_var("IRC_PASSWORD", "secret123");
assert_eq!(BridgeConfig::irc_server_password().as_deref(), Some("secret123"));
std::env::remove_var("IRC_PASSWORD");
assert!(BridgeConfig::irc_server_password().is_none());
}
#[test]
fn test_access_token_from_env() {
std::env::set_var("OWNCAST_ACCESS_TOKEN", "test-token-123");