If you are willing to ignore rawset and rawget (which override metatables), here is an example of protecting a "key" in _G:
local myTable = {
hi = function() return "hi" end,
value = 5
}
setmetatable(_G, {
__index = myTable,
__newindex = function() error("You cannot modify _G") end,
__metatable = "You cannot modify the metatable of _G"
})
print(_G.value)
print(_G.hi())
print(getmetatable(_G))
_G.value = 3
setmetatable(_G, nil)
This assumes that _G is empty when the script runs (which it is by default). You can just as easily protect a table within _G, rather than forcing all of _G to the purposes of this script, but other scripts could simply remove the table from _G. Note that this particular implementation means that no other script can add anything to _G. You can improve the script above to allow additions to _G so long as the key isn't in 'myTable':
__newindex = function(t, key, value)
if myTable[key] then error("You cannot modify _G." .. tostring(key)) end
rawset(_G, key, value)
end,
Note, however, that none of this will prevent rawget and rawset from messing up _G, since those functions ignore metatables.
I would recommend using a ModuleScript instead of _G. If your script will be used by someone else in their own place, it's smarter to let them mess up your API if they want (it won't impact your original script or your own place, so it shouldn't be a big deal). A malicious script can do tons of damage if it's on the server-side (ex delete the contents of the workspace or flood it with tons of new parts) - there's no point in trying to protect from every possible bad thing a script could do, especially when it's not even your own place. If these potentially malicious scripts are a part of your place, simply remove the ones that make a mess of things, or read over the potentially malicious scripts to make sure they don't do anything stupid. The above solution for _G will also work just as easily for ModuleScripts, so consider using that instead.
The legitimate use of preventing other scripts from tampering with an API is to communicate to users of the API that the change they just attempted is illegal. For this case, using metatables should be sufficient.
1 comment
By overrinding it I meant prevent from overriding Access since my API table is in the script, not _G.