Skip to content

Commit

Permalink
Fixed songs loops and allow URLs from admin radios
Browse files Browse the repository at this point in the history
- Fixed songs ending with "sound stopped" on song switch
- Radios owned by admins will allow all URLs as admins are a trusted sources of media. ConVar: `sv_streamradio_url_whitelist_trust_admin_radios 0/1`, Enabled by default.
  • Loading branch information
Grocel committed Nov 14, 2023
1 parent f46b5c1 commit 1e4e185
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 11 deletions.
18 changes: 18 additions & 0 deletions lua/entities/base_streamradio.lua
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ function ENT:GetOrCreateStream()
return call("StreamOnSearch", ...)
end

stream.CanIgnoreWhitelist = function( ... )
return call("StreamCanIgnoreWhitelist", ...)
end

stream.OnMute = function( ... )
return call("StreamOnMute", ...)
end
Expand Down Expand Up @@ -198,6 +202,20 @@ function ENT:StreamOnSearch()
return true
end

function ENT:StreamCanIgnoreWhitelist()
if not StreamRadioLib.IsUrlWhitelistAdminRadioTrusted() then
return false
end

local owner = self:GetRealRadioOwner()
if LIBUtil.IsAdmin(owner) then
-- Admins are allowed to bypass built-in whitelisting for better UX.
return true
end

return false
end

function ENT:StreamOnRetry()
self:CheckTransmitState()

Expand Down
33 changes: 29 additions & 4 deletions lua/streamradio_core/classes/stream.lua
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ function CLASS:FastThink()

local masterLength = self:GetMasterLength()

self.State.Ended = self:HasEnded()
self.State.Ended = self:HasEndedInternal()
self.State.Seeking = self:_IsSeekingInternal()
self.State.Length = self:GetLength()
self.State.ValidChannel = IsValid(self.Channel)
Expand Down Expand Up @@ -721,6 +721,10 @@ function CLASS:DoUnexpectedStopCheck()
return
end

if self:HasEnded() then
return
end

self:KillStream()
end

Expand Down Expand Up @@ -752,6 +756,14 @@ function CLASS:IsAllowedInternalUrl(url, callback, logFailure)
end

function CLASS:IsAllowedExternalUrl(url, callback)
if self:CallHook("CanIgnoreWhitelist", url) then
-- Sometimes we don't want/need to check the addon's whitelist
-- E.g. when the owner of the radio entity is an admin.

callback(self, true, nil)
return
end

StreamRadioLib.Whitelist.IsAllowedAsync(url, function(allowed)
if not IsValid(self) then return end

Expand Down Expand Up @@ -792,7 +804,7 @@ function CLASS:DoUrlBackgroundCheck()
return
end

if not self:IsOnline() then
if not self:IsOnlineUrl() then
return
end

Expand Down Expand Up @@ -825,7 +837,7 @@ function CLASS:DoUrlBackgroundCheck()
return
end

if not self:IsOnline() then
if not self:IsOnlineUrl() then
return
end

Expand Down Expand Up @@ -2050,6 +2062,14 @@ function CLASS:HasEnded()
return false
end

return self.State.Ended
end

function CLASS:HasEndedInternal()
if not self.Valid then
return false
end

local curtime = 0
local length = 0

Expand Down Expand Up @@ -2849,6 +2869,11 @@ function CLASS:OnSearch(url)
return true -- Allow url to be played
end

function CLASS:CanIgnoreWhitelist(url)
-- override
return false -- Ignore the build-in whitelist?
end

function CLASS:OnClose()
-- override
end
Expand All @@ -2864,7 +2889,7 @@ end

function CLASS:OnRetry(err, internalUrl, state, interface)
-- override
return true -- retry again?
return true -- Retry again?
end

function CLASS:OnError(err)
Expand Down
13 changes: 11 additions & 2 deletions lua/streamradio_core/client/cl_vgui.lua
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ function PANEL:GetOrCreateStream()
self:UpdateURLState(STATE_ERROR)
end

stream.OnRetry = function( thisStream, err )
stream.OnRetry = function( thisStream )
if not IsValid(self) then
return false
end
Expand All @@ -316,7 +316,7 @@ function PANEL:GetOrCreateStream()
return true
end

stream.OnSearch = function( thisStream, err )
stream.OnSearch = function( thisStream )
if not IsValid( self ) then
return false
end
Expand All @@ -325,6 +325,15 @@ function PANEL:GetOrCreateStream()
return true
end

stream.CanIgnoreWhitelist = function( thisStream )
if not IsValid( self ) then
return false
end

-- This stream is for the local client only and safe to use. No whitelist is needed here. Avoids UX problems also.
return true
end

stream.OnDownload = function( thisStream, url, interface )
return false
end
Expand Down
4 changes: 4 additions & 0 deletions lua/streamradio_core/client/cl_whitelist.lua
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ function LIB.QuickWhitelistAdd(url)
net.WriteString(url)
net.WriteBool(true)
net.SendToServer()

g_whitelistCache:Remove(url)
end

function LIB.QuickWhitelistRemove(url)
Expand All @@ -179,6 +181,8 @@ function LIB.QuickWhitelistRemove(url)
net.WriteString(url)
net.WriteBool(false)
net.SendToServer()

g_whitelistCache:Remove(url)
end

return true
Expand Down
5 changes: 5 additions & 0 deletions lua/streamradio_core/client/settings/admin.lua
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ local function AddSecurityMenuPanel(CPanel)
subpanel:AddItem(LIBMenu.GetLabel("The whitelist is based of the installed playlists. Edit them to change the whitelist or use the quick whitelist options on a radio entity."))
subpanel:AddItem(LIBMenu.GetLabel("It is always disabled on single player."))

subpanel:CheckBox(
"Always trust radios owned by admins (skips whitelist)",
"sv_streamradio_url_whitelist_trust_admin_radios"
)

subpanel:AddItem(LIBMenu.GetSpacer())

subpanel:AddItem(LIBMenu.GetWhitelistFAQButton())
Expand Down
23 changes: 22 additions & 1 deletion lua/streamradio_core/convar.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ local StreamRadioLib = StreamRadioLib
local g_allowSpectrum = false
local g_enableUrlWhitelist = true
local g_enableUrlWhitelistOnCFCWhitelist = true
local g_enableUrlWhitelistTrustAdminRadios = true

local g_lastThink = 0

Expand All @@ -27,6 +28,13 @@ local g_cvUrlWhitelistEnableOnCFCWhitelist = CreateConVar(
"Enables built-in Stream URL whitelist even if 'CFC Client HTTP Whitelist' is installed and 'sv_streamradio_url_whitelist_enable' is on. Otherwise built-in whitelist stays inactive as long CFC's one is active. 0 = Disable, 1 = Enable, Default: 0"
)

local g_cvUrlWhitelistTrustAdminRadios = CreateConVar(
"sv_streamradio_url_whitelist_trust_admin_radios",
"1",
bit.bor( FCVAR_NOTIFY, FCVAR_ARCHIVE, FCVAR_GAMEDLL, FCVAR_REPLICATED ),
"Trust Stream URLs from radios owned by admins. Skips built-in whitelist checks for admin radios. 0 = No, 1 = Yes, Default: 1"
)

local g_cvRebuildCommunityPlaylists = CreateConVar(
"sv_streamradio_rebuildplaylists_community_auto",
"2",
Expand Down Expand Up @@ -66,6 +74,11 @@ function StreamRadioLib.IsUrlWhitelistEnabledOnCFCWhitelist()
return true
end

function StreamRadioLib.IsUrlWhitelistAdminRadioTrusted()
if not g_enableUrlWhitelistTrustAdminRadios then return false end
return true
end

function StreamRadioLib.GetRebuildCommunityPlaylistsMode()
local mode = g_cvRebuildCommunityPlaylists:GetInt()

Expand Down Expand Up @@ -94,7 +107,7 @@ local function calcUrlWhitelistEnabled()
end

if StreamRadioLib.Cfchttp.CanCheckWhitelist() then
-- CFC Client HTTP whitelist is available, disable our's then.
-- CFC Client HTTP whitelist is available, disable our whitelist system then.
return false
end

Expand All @@ -108,6 +121,13 @@ local function calcUrlWhitelistEnabledOnCFCWhitelist()
return true
end

local function calcUrlWhitelistEnabledTrustAdminRadios()
if game.SinglePlayer() then return true end
if not g_cvUrlWhitelistTrustAdminRadios:GetBool() then return false end

return true
end

local function updateUrlWhitelistEnabled()
if CLIENT then return end

Expand All @@ -123,6 +143,7 @@ StreamRadioLib.Hook.Add("Think", "ConvarsUpdate", function()
local old_enableUrlWhitelist = g_enableUrlWhitelist
local old_enableUrlWhitelistOnCFCWhitelist = g_enableUrlWhitelistOnCFCWhitelist

g_enableUrlWhitelistTrustAdminRadios = calcUrlWhitelistEnabledTrustAdminRadios()
g_enableUrlWhitelistOnCFCWhitelist = calcUrlWhitelistEnabledOnCFCWhitelist()
g_enableUrlWhitelist = calcUrlWhitelistEnabled()

Expand Down
27 changes: 25 additions & 2 deletions lua/streamradio_core/properties.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ table.Empty(LIB)
local LIBNet = StreamRadioLib.Net
local LIBError = StreamRadioLib.Error
local LIBUtil = StreamRadioLib.Util
local LIBUrl = StreamRadioLib.Url

local g_mainOptionAdded = false
local g_subOptions = {}
Expand Down Expand Up @@ -1028,6 +1029,14 @@ LIB.AddSubOption("admin_title", {
if not LIBUtil.IsAdmin( ply ) then return false end
if not LIB.CanBeTargeted( ent, ply ) then return false end

if StreamRadioLib.IsUrlWhitelistEnabled() then
local url = ent:GetStreamURL()
if url ~= "" then
-- Trigger updating the cache in the background if needed
StreamRadioLib.Whitelist.IsAllowedAsync(url)
end
end

local allowed = LIB.CheckFilters(
{
"admin_whitelist_add",
Expand Down Expand Up @@ -1055,18 +1064,25 @@ LIB.AddSubOption("admin_whitelist_add", {
Filter = function( self, ent, ply )
if not LIBUtil.IsAdmin( ply ) then return false end
if not LIB.CanBeTargeted( ent, ply ) then return false end
if not StreamRadioLib.IsUrlWhitelistEnabled() then return false end

local url = ent:GetStreamURL()
if url == "" then return false end

if StreamRadioLib.Whitelist.IsAllowedSync(url) then return false end
if LIBUrl.IsOfflineURL(url) then
return false
end

if StreamRadioLib.Whitelist.IsAllowedSync(url) then return false end
return true
end,

Action = function( self, ent )
local url = ent:GetStreamURL()
StreamRadioLib.Whitelist.QuickWhitelistAdd(url)

-- Trigger updating the cache in the background if needed
StreamRadioLib.Whitelist.IsAllowedAsync(url)
end,
})

Expand All @@ -1079,18 +1095,25 @@ LIB.AddSubOption("admin_whitelist_remove", {
Filter = function( self, ent, ply )
if not LIBUtil.IsAdmin( ply ) then return false end
if not LIB.CanBeTargeted( ent, ply ) then return false end
if not StreamRadioLib.IsUrlWhitelistEnabled() then return false end

local url = ent:GetStreamURL()
if url == "" then return false end

if not StreamRadioLib.Whitelist.IsAllowedSync(url) then return false end
if LIBUrl.IsOfflineURL(url) then
return false
end

if not StreamRadioLib.Whitelist.IsAllowedSync(url) then return false end
return true
end,

Action = function( self, ent )
local url = ent:GetStreamURL()
StreamRadioLib.Whitelist.QuickWhitelistRemove(url)

-- Trigger updating the cache in the background if needed
StreamRadioLib.Whitelist.IsAllowedAsync(url)
end,
})

Expand Down
4 changes: 2 additions & 2 deletions materials/3dstreamradio/_data/version.vmt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
436
1699498359
437
1699922407

0 comments on commit 1e4e185

Please sign in to comment.