Understanding bitwise operators (for permission systems)

Hey there! Back in September whilst I was working on my organisation system I had to somehow create a permission system with bit flags. (The bit flags weren't a requirement, it was a personal one.)

So I started Googling on how I'd approach this. If you're anything like me, I thought it'd be a hard to understand subject involving lots of math. But as it turns out, it's much easier than that.

Bit flags permission system in GLua

GLua includes Lua BitOp, so that's what I'm using. There's a native implementation of bitwise operators since Lua 5.3.

Config

XYZ_ORGS.Config.Permissions = {
	-- Thanks https://gist.github.com/ThomasBurleson/0ae1e9e30d9397da7110e595d21e18e3 <3
	ALL = bit.lshift(1, 0),

	INVITE = bit.lshift(1, 1),
	KICK = bit.lshift(1, 2),
	--BAN = bit.lshift(1, 3),
	MANAGE_UPGRADES = bit.lshift(1, 3),
	WITHDRAW  = bit.lshift(1, 4),
	DEPOSIT  = bit.lshift(1, 5),
	MANAGE_PERMISSIONS = bit.lshift(1, 6),
}

As you can see I defined 6 permissions. All, which is totally unneeded but I left it in. Invite, which is 1 shifted left by 1 bit. Kick, which is 1 shifted left by 2 bits. Manage Upgrades, which is 1 shifted left by 3 bits. I think you get the picture.

So how do we actually use this to check if someone has access to something? Again, it's not that hard.

function XYZ_ORGS.Core.HasPerms(perms, permtocheck, ply, dontNotify)
	if bit.band(perms, bit.bor(XYZ_ORGS.Config.Permissions.ALL, XYZ_ORGS.Config.Permissions[permtocheck])) == 0 then 
		if SERVER and not dontNotify then
			XYZShit.Msg("Organizations", XYZ_ORGS.Config.Color, "No permission.", ply)
		end
		return false
	end
	return true
end

Let's look at what this function does:

First of all, bit.band will perform a bitwise AND on the variable 'perms' and the result of the bit.bor call. So what does the bit.bor do? It performs a bitwise OR on multiple values, so in this case what I'm doing is checking if they either have the ALL permission, or the 'permtocheck' permission. The function then checks if the result is 0, meaning 'perms' doesn't have the permission of ALL, nor 'permtocheck'. If yes, it's going to notify the user (unless dontNotify is true). It then returns either true, or false.

Using this function

Let's use this function in an example:

net.Receive("xyz_orgs_withdraw", function(_, ply)
	-- ...
	if not XYZ_ORGS.Core.HasPerms(plyorg.roles[plyorg.members[ply:SteamID64()]].perms, 'WITHDRAW', ply) then return end

In this example, we check if HasPerms returns false by feeding it the member's permission value, and checking it against the 'WITHDRAW' permission. If they do not have permission, it will return and they will automatically be notified by the HasPerms function.

I hope this helped you understand Bit Flags. If not, feel free to let me know.

A special thanks to the following resources, which helped me understand this myself;