-
Notifications
You must be signed in to change notification settings - Fork 529
/
cl_main.lua
195 lines (175 loc) · 6.12 KB
/
cl_main.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
-- =============================================
-- ServerCtx Synchronization
-- =============================================
ServerCtx = false
--- Updates ServerCtx based on GlobalState and will send it to NUI
--- NOTE: for now the ServerCtx is only being set when the menu tries to load (enabled or not)
function updateServerCtx()
stateBagServerCtx = GlobalState.txAdminServerCtx
if stateBagServerCtx == nil then
debugPrint('^3ServerCtx fallback support activated.')
TriggerServerEvent('txsv:req:serverCtx')
else
ServerCtx = stateBagServerCtx
debugPrint('^2ServerCtx updated from global state')
end
end
RegisterNetEvent('txcl:setServerCtx', function(ctx)
if type(ctx) ~= 'table' then return end
ServerCtx = ctx
debugPrint('^2ServerCtx updated from server event.')
sendMenuMessage('setServerCtx', ServerCtx)
end)
-- =============================================
-- Announcement, DirectMessage and Warn handling
-- =============================================
-- Dispatch Announcements
RegisterNetEvent('txcl:showAnnouncement', function(message, author)
sendMenuMessage(
'addAnnounceMessage',
{
message = message,
author = author
}
)
end)
RegisterNetEvent('txcl:showDirectMessage', function(message, author)
sendMenuMessage(
'addDirectMessage',
{
message = message,
author = author
}
)
end)
-- TODO: remove [SPACE] holding requirement?
local dismissKey, dismissKeyGroup
if IS_FIVEM then
dismissKey = 22
dismissKeyGroup = 0
else
dismissKey = 0xD9D0E1C0
dismissKeyGroup = 1
end
RegisterNetEvent('txcl:showWarning', function(author, reason)
toggleMenuVisibility(false)
sendMenuMessage('setWarnOpen', {
reason = reason,
warnedBy = author
})
CreateThread(function()
local countLimit = 100 --10 seconds
local count = 0
while true do
Wait(100)
if IsControlPressed(dismissKeyGroup, dismissKey) then
count = count + 1
if count >= countLimit then
sendMenuMessage('closeWarning')
return
elseif math.fmod(count, 10) == 0 then
sendMenuMessage('pulseWarning')
end
else
count = 0
end
end
end)
end)
-- =============================================
-- Other stuff
-- =============================================
-- Removing unwanted chat suggestions
-- We only want suggestion for: /tx, /txAdmin-reauth
-- The suggestion is added after 500ms, so we need to wait more
CreateThread(function()
Wait(1000)
local suggestionsToRemove = {
--Commands
'/txadmin',
'/txaPing',
'/txaKickAll',
'/txaEvent',
'/txaReportResources',
'/txaSetDebugMode',
--Keybinds
'/txAdmin:menu:noClipToggle',
'/txAdmin:menu:openPlayersPage',
'/txAdmin:menu:togglePlayerIDs',
--Convars
'/txAdmin-version',
'/txAdmin-locale',
'/txAdmin-localeFile',
'/txAdmin-verbose',
'/txAdmin-luaComHost',
'/txAdmin-luaComToken',
'/txAdmin-checkPlayerJoin',
'/txAdmin-pipeToken',
'/txAdmin-debugMode',
'/txAdmin-hideDefaultAnnouncement',
'/txAdmin-hideDefaultDirectMessage',
'/txAdmin-hideDefaultWarning',
'/txAdmin-hideDefaultScheduledRestartWarning',
'/txAdminServerMode',
--Menu convars
'/txAdmin-menuEnabled',
'/txAdmin-menuAlignRight',
'/txAdmin-menuPageKey',
'/txAdmin-menuPlayerIdDistance',
'/txAdmin-menuDrunkDuration'
}
for _, suggestion in ipairs(suggestionsToRemove) do
TriggerEvent('chat:removeSuggestion', suggestion)
end
end)
-- =============================================
-- Helper to protect the NUI callbacks from CSRF attacks
-- NOTE: This is a temporary fix for the NUI callback Origin issue
-- =============================================
--- Check if a NUI callback is from the correct Origin
--- technically no request should come from nui://monitor, since the manifest version is cerulean
---@param headers table
---@return boolean
function IsNuiRequestOriginValid(headers)
if type(headers) ~= 'table' then
return false --no clue
end
if headers['Origin'] == nil then
return true --probably legacy page
end
if type(headers['Origin']) ~= 'string' or headers['Origin'] == '' then
return false --no clue
end
if headers['Origin'] == 'https://cfx-nui-monitor' then
return true --probably self
end
if headers['Origin'] == 'https://monitor' then
return true --probably legacy iframe inside web iframe
end
-- warn admin of possible csrf attempt
if menuIsAccessible and sendPersistentAlert then
local msg = ('ATTENTION! txAdmin received a NUI message from the origin "%s" which is not approved. This likely means that that resource is vulnerable to XSS which has been exploited to inject txAdmin commands. It is recommended that you fix the vulnerability or remove that resource completely. For more information: discord.gg/txAdmin.'):format(headers['Origin'])
sendPersistentAlert('csrfWarning', 'error', msg, false)
end
return false
end
--- Wrapper for RegisterRawNuiCallback which mimics the behavior of RegisterNUICallback
--- but checks the origin of the request to prevent CSRF attacks
function RegisterSecureNuiCallback(callbackName, funcCallback)
RegisterRawNuiCallback(callbackName, function(req, nuiCallback)
if not IsNuiRequestOriginValid(req.headers) then
debugPrint(("^1Invalid NUI callback origin for %s"):format(callbackName))
return nuiCallback({
status = 403,
body = '{}',
})
end
-- calls the function
funcCallback(json.decode(req.body), function(data)
nuiCallback({
status = 200,
body = type(data) == 'table' and json.encode(data) or '{}',
})
end)
end)
end