From 44917d26090d4bfc7256dfcfd914f12c20652a8e Mon Sep 17 00:00:00 2001 From: Pierce Date: Mon, 28 Aug 2023 17:00:36 -0400 Subject: [PATCH 1/8] add convar and hook to disable whitelist and file checking --- lua/autorun/webaudio.lua | 7 ++++++- lua/webaudio/receiver.lua | 31 +++++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/lua/autorun/webaudio.lua b/lua/autorun/webaudio.lua index 362ffdc..1530f17 100644 --- a/lua/autorun/webaudio.lua +++ b/lua/autorun/webaudio.lua @@ -68,6 +68,7 @@ end -- SERVER local WAAdminOnly = CreateConVar("wa_admin_only", "0", FCVAR_REPLICATED, "Whether creation of WebAudio objects should be limited to admins. 0 for everyone, 1 for admins, 2 for superadmins. wa_enable_sv takes precedence over this", 0, 2) local WASCCompat = CreateConVar("wa_sc_compat", "0", FCVAR_ARCHIVE, "Whether streamcore-compatible functions should be generated for E2.", 0, 1) +local WACheckFileContent = CreateConVar("wa_sc_checkfilecontent", "1", FCVAR_REPLICATED, "Do NOT disable this unless you have other security measures in place, disabling this allows bypassing the whitelist. Whether webaudio should check the content of streams before playing", 0, 1) -- Max in total is ~1023 from ID_LEN writing a 10 bit uint. Assuming ~30 players max using webaudio, can only give ~30. local WAMaxStreamsPerUser = CreateConVar("wa_stream_max", "5", FCVAR_REPLICATED, "Max number of streams a player can have at once.", 1, 30) @@ -681,6 +682,9 @@ local function isWhitelistedURL(url) if not isstring(url) then return false end url = url:Trim() + local isWhitelisted = hook.Run("WA_IsWhitelistedURL", url) + if isWhitelisted ~= nil then return isWhitelisted end + local relative = url:match("^https?://www%.(.*)") or url:match("^https?://(.*)") if not relative then return false end @@ -770,6 +774,7 @@ WebAudio.Common = { WAAdminOnly = WAAdminOnly, WAMaxStreamsPerUser = WAMaxStreamsPerUser, WASCCompat = WASCCompat, + WACheckFileContent = WACheckFileContent, -- Shared WAEnabled = WAEnabled, @@ -797,4 +802,4 @@ else include("webaudio/interface.lua") end -return WebAudio.Common \ No newline at end of file +return WebAudio.Common diff --git a/lua/webaudio/receiver.lua b/lua/webaudio/receiver.lua index a790757..55e0fb7 100644 --- a/lua/webaudio/receiver.lua +++ b/lua/webaudio/receiver.lua @@ -90,6 +90,26 @@ timer.Create("wa_think", 100 / 1000, 0, function() end end) +---@param url string +---@param onSuccess fun() +---@param onError fun(err: string) +local function checkStreamContents(url, onSuccess, onError) + if not WebAudio.Common.WACheckFileContent:GetBool() then + onSuccess() + return + end + + http.Fetch(url, function(body, _, _) + if body:find("#EXTM3U", 1, true) then + onError("Cannot create stream with unwhitelisted file format (m3u)") + end + + onSuccess() + end, function(err) + onError("HTTP error:" ..err) + end) +end + net.Receive("wa_create", function(len) local id, url, owner = WebAudio.readID(), net.ReadString(), net.ReadEntity() local verbosity = Verbosity:GetInt() @@ -141,12 +161,7 @@ net.Receive("wa_create", function(len) notify("User %s(%s) created WebAudio object with url [%q]", owner:Nick(), owner:SteamID64() or "multirun", url) - http.Fetch(url, function(body, size, headers) - if body:find("#EXTM3U", 1, true) then - streamFailed() - return warn("User %s(%s) tried to create WebAudio object with unwhitelisted file format (m3u)", owner:Nick(), owner:SteamID64() or "multirun") - end - + checkStreamContents(url, function() sound.PlayURL(url, "3d noblock noplay", function(bass, errid, errname) if errid then streamFailed() @@ -209,7 +224,7 @@ net.Receive("wa_create", function(len) end) end, function(err) streamFailed() - return warn("HTTP error when creating WebAudio receiver with id %d, Error [%q]", id, err) + return warn("Error when creating WebAudio object, User %s(%s), Error: %s", owner:Nick(), owner:SteamID64() or "multirun", err) end) WebAudio.new(url, owner, nil, id) -- Register object @@ -403,4 +418,4 @@ cvars.AddChangeCallback("wa_enable", function(convar, old, new) net.Start("wa_enable", true) net.WriteBool(enabled) -- Tell the server to subscribe/unsubscribe us from net messages net.SendToServer() -end, "wa_enable") \ No newline at end of file +end, "wa_enable") From be0f0db6694eae3991a3673652bf44b297a43540 Mon Sep 17 00:00:00 2001 From: Pierce Date: Sun, 3 Sep 2023 00:40:13 -0400 Subject: [PATCH 2/8] use hooks instead of convars for file content check --- lua/webaudio/receiver.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/webaudio/receiver.lua b/lua/webaudio/receiver.lua index 55e0fb7..52b921f 100644 --- a/lua/webaudio/receiver.lua +++ b/lua/webaudio/receiver.lua @@ -94,7 +94,7 @@ end) ---@param onSuccess fun() ---@param onError fun(err: string) local function checkStreamContents(url, onSuccess, onError) - if not WebAudio.Common.WACheckFileContent:GetBool() then + if hook.Run("WA_ShouldCheckFileContent", url) == false then onSuccess() return end From 89ee98c25916a63ecb6e80b4e03fc8458959704f Mon Sep 17 00:00:00 2001 From: Pierce Date: Sun, 3 Sep 2023 00:41:54 -0400 Subject: [PATCH 3/8] add new check to checkStreamContents --- lua/webaudio/receiver.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lua/webaudio/receiver.lua b/lua/webaudio/receiver.lua index 52b921f..e380f16 100644 --- a/lua/webaudio/receiver.lua +++ b/lua/webaudio/receiver.lua @@ -94,7 +94,7 @@ end) ---@param onSuccess fun() ---@param onError fun(err: string) local function checkStreamContents(url, onSuccess, onError) - if hook.Run("WA_ShouldCheckFileContent", url) == false then + if hook.Run("WA_ShouldCheckStreamContent", url) == false then onSuccess() return end @@ -104,6 +104,10 @@ local function checkStreamContents(url, onSuccess, onError) onError("Cannot create stream with unwhitelisted file format (m3u)") end + if body:find("[playlist]", 1, true) then + onError("Cannot create stream with unwhitelisted file format (pls)") + end + onSuccess() end, function(err) onError("HTTP error:" ..err) From 2572585944fd136c07b605d88aec419348ba9c50 Mon Sep 17 00:00:00 2001 From: Pierce Date: Sun, 3 Sep 2023 00:43:18 -0400 Subject: [PATCH 4/8] remove unused convars --- lua/autorun/webaudio.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/lua/autorun/webaudio.lua b/lua/autorun/webaudio.lua index 1530f17..cc7d1cd 100644 --- a/lua/autorun/webaudio.lua +++ b/lua/autorun/webaudio.lua @@ -68,7 +68,6 @@ end -- SERVER local WAAdminOnly = CreateConVar("wa_admin_only", "0", FCVAR_REPLICATED, "Whether creation of WebAudio objects should be limited to admins. 0 for everyone, 1 for admins, 2 for superadmins. wa_enable_sv takes precedence over this", 0, 2) local WASCCompat = CreateConVar("wa_sc_compat", "0", FCVAR_ARCHIVE, "Whether streamcore-compatible functions should be generated for E2.", 0, 1) -local WACheckFileContent = CreateConVar("wa_sc_checkfilecontent", "1", FCVAR_REPLICATED, "Do NOT disable this unless you have other security measures in place, disabling this allows bypassing the whitelist. Whether webaudio should check the content of streams before playing", 0, 1) -- Max in total is ~1023 from ID_LEN writing a 10 bit uint. Assuming ~30 players max using webaudio, can only give ~30. local WAMaxStreamsPerUser = CreateConVar("wa_stream_max", "5", FCVAR_REPLICATED, "Max number of streams a player can have at once.", 1, 30) @@ -774,7 +773,6 @@ WebAudio.Common = { WAAdminOnly = WAAdminOnly, WAMaxStreamsPerUser = WAMaxStreamsPerUser, WASCCompat = WASCCompat, - WACheckFileContent = WACheckFileContent, -- Shared WAEnabled = WAEnabled, From 7e15b05743fb7765d8b7f0348f68625526ebf105 Mon Sep 17 00:00:00 2001 From: Pierce Date: Sun, 3 Sep 2023 01:15:37 -0400 Subject: [PATCH 5/8] return when onError called for checkStreamContents --- lua/webaudio/receiver.lua | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lua/webaudio/receiver.lua b/lua/webaudio/receiver.lua index e380f16..7bdbc17 100644 --- a/lua/webaudio/receiver.lua +++ b/lua/webaudio/receiver.lua @@ -95,17 +95,16 @@ end) ---@param onError fun(err: string) local function checkStreamContents(url, onSuccess, onError) if hook.Run("WA_ShouldCheckStreamContent", url) == false then - onSuccess() - return + return onSuccess() end http.Fetch(url, function(body, _, _) if body:find("#EXTM3U", 1, true) then - onError("Cannot create stream with unwhitelisted file format (m3u)") + return onError("Cannot create stream with unwhitelisted file format (m3u)") end if body:find("[playlist]", 1, true) then - onError("Cannot create stream with unwhitelisted file format (pls)") + return onError("Cannot create stream with unwhitelisted file format (pls)") end onSuccess() From 8c9404a8009a79fc166e4ed022cf377380485d77 Mon Sep 17 00:00:00 2001 From: Pierce Date: Sun, 3 Sep 2023 01:21:37 -0400 Subject: [PATCH 6/8] include id in error message for checking stream content --- lua/webaudio/receiver.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/webaudio/receiver.lua b/lua/webaudio/receiver.lua index 7bdbc17..86cbb10 100644 --- a/lua/webaudio/receiver.lua +++ b/lua/webaudio/receiver.lua @@ -227,7 +227,7 @@ net.Receive("wa_create", function(len) end) end, function(err) streamFailed() - return warn("Error when creating WebAudio object, User %s(%s), Error: %s", owner:Nick(), owner:SteamID64() or "multirun", err) + return warn("Error when creating WebAudio object with id: %s, User %s(%s), Error: %s", id, owner:Nick(), owner:SteamID64() or "multirun", err) end) WebAudio.new(url, owner, nil, id) -- Register object From ef62349e2f422cf3e587f63bb2c8c22f38a9c69c Mon Sep 17 00:00:00 2001 From: Pierce Date: Sun, 3 Sep 2023 01:34:19 -0400 Subject: [PATCH 7/8] whitespace changes --- lua/webaudio/receiver.lua | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lua/webaudio/receiver.lua b/lua/webaudio/receiver.lua index 86cbb10..f241af0 100644 --- a/lua/webaudio/receiver.lua +++ b/lua/webaudio/receiver.lua @@ -94,23 +94,23 @@ end) ---@param onSuccess fun() ---@param onError fun(err: string) local function checkStreamContents(url, onSuccess, onError) - if hook.Run("WA_ShouldCheckStreamContent", url) == false then - return onSuccess() + if hook.Run("WA_ShouldCheckStreamContent", url) == false then + return onSuccess() end http.Fetch(url, function(body, _, _) if body:find("#EXTM3U", 1, true) then - return onError("Cannot create stream with unwhitelisted file format (m3u)") + return onError("Cannot create stream with unwhitelisted file format (m3u)") end if body:find("[playlist]", 1, true) then return onError("Cannot create stream with unwhitelisted file format (pls)") end - onSuccess() - end, function(err) - onError("HTTP error:" ..err) - end) + onSuccess() + end, function(err) + onError("HTTP error:" ..err) + end) end net.Receive("wa_create", function(len) From 4a47b9793f2ec0663cea916149c38ad555a2658a Mon Sep 17 00:00:00 2001 From: Pierce Date: Sun, 3 Sep 2023 01:35:31 -0400 Subject: [PATCH 8/8] whitespace changes --- lua/webaudio/receiver.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/webaudio/receiver.lua b/lua/webaudio/receiver.lua index f241af0..826eaa0 100644 --- a/lua/webaudio/receiver.lua +++ b/lua/webaudio/receiver.lua @@ -96,7 +96,7 @@ end) local function checkStreamContents(url, onSuccess, onError) if hook.Run("WA_ShouldCheckStreamContent", url) == false then return onSuccess() - end + end http.Fetch(url, function(body, _, _) if body:find("#EXTM3U", 1, true) then @@ -109,7 +109,7 @@ local function checkStreamContents(url, onSuccess, onError) onSuccess() end, function(err) - onError("HTTP error:" ..err) + onError("HTTP error:" .. err) end) end