Introducing the Ban API and Alt Account Detection

It generally works over cookies, I don’t think IP would ever be used unless the offender creates a lot of accounts which they already take action on.

1 Like

The whole thought process behind it seems sloppy, thankfully it seems like its still im beta so i have some hope it will change

1 Like

I’ve smashed together a few things.
I’m not sure if it all works yet, but it’s a template you could look at.

This allows for these commands:

  1. Ban Command
  • Syntax: ;ban UserID [Duration] [Reason]
  • Description: Bans the specified user with an optional reason.
  • Example: ;ban 123456789 1h Cheating
  1. Unban Command
  • Syntax: ;unban UserID [Reason]
  • Description: Unbans the specified user with an optional reason.
  • Example: ;unban 123456789 Apology accepted
  1. Ban History Command
  • Syntax: ;banhistory UserID
  • Description: Retrieves and displays the ban history of the specified user.
  • Example: ;banhistory 123456789
  1. Silent Ban Command
  • Syntax: /ban UserID [Duration] [Reason]
  • Description: Silently bans the specified user with an optional reason. Results are sent directly to the executing player.
  • Example: /ban 123456789 1h Cheating
  1. Silent Unban Command
  • Syntax: /unban UserID [Reason]
  • Description: Silently unbans the specified user with an optional reason. Results are sent directly to the executing player.
  • Example: /unban 123456789 Apology accepted
  1. Silent Ban History Command
  • Syntax: /banhistory UserID
  • Description: Silently retrieves and displays the ban history of the specified user. Results are sent directly to the executing player.
  • Example: /banhistory 123456789

Usage Notes

  • Prefix: Commands prefixed with ; are public, visible to all players in the chat.
  • Silent Prefix: Commands prefixed with / are silent, and results are sent only to the player who issued the command.
  • Reason Parameter: The reason for banning or unbanning is optional. If not provided, it defaults to “No reason provided”.
  • Permissions: Only players with the necessary permissions (specified user IDs or group ranks) can execute these commands.

Special Considerations

  • Studio Testing: The script allows the use of special UserIDs (negative values) for testing in Roblox Studio.
  • Ban/Unban Permissions: Specific user IDs and group ranks are allowed to ban or unban users, ensuring proper access control.

This setup ensures that only authorized players can manage bans and unbans, and allows for silent execution of commands when needed.

Code
local Players = game:GetService("Players")
local HttpService = game:GetService("HttpService")
local RunService = game:GetService("RunService")
local prefix = ";" -- Change this prefix as per your command setup
local silentPrefix = "/" -- Prefix for silent commands

-- Configuration: Allowed UserIDs, Groups, and Specific Ranks for Ban/Unban
local allowedUserIds = {4309939, -1} -- UserIds of the admins

local allowedGroups = {
	{3057028, 255, 254, 250}, -- Group ID and ranks of the allowed groups
	{3057028, 255, 252, 248}
	-- Add more groups with their respective ranks in the format {groupId, rank1, rank2, ...}
}

local banRank = {3057028, 255, 254, 250} -- Group ID and ranks allowed to ban
local unbanRank = {3057028, 254, 253, 252} -- Group ID and ranks allowed to unban

-- Function to check if a player is in a specific group with a required rank
local function isInGroupWithRank(player, groupId, ranks)
	if player:IsInGroup(groupId) then
		local playerRank = player:GetRankInGroup(groupId)
		for _, rank in ipairs(ranks) do
			if playerRank == rank then
				return true
			end
		end
	end
	return false
end

-- Function to check if a player can ban
local function canBan(player)
	-- Check if player is in allowed UserIDs
	for _, userId in ipairs(allowedUserIds) do
		if player.UserId == userId then
			return true
		end
	end

	-- Check if player is in allowed groups with sufficient rank for banning
	for _, groupInfo in ipairs(banRank) do
		local groupId = groupInfo[1]
		if isInGroupWithRank(player, groupId, groupInfo) then
			return true
		end
	end

	return false
end

-- Function to check if a player can unban
local function canUnban(player)
	-- Check if player is in allowed UserIDs
	for _, userId in ipairs(allowedUserIds) do
		if player.UserId == userId then
			return true
		end
	end

	-- Check if player is in allowed groups with sufficient rank for unbanning
	for _, groupInfo in ipairs(unbanRank) do
		local groupId = groupInfo[1]
		if isInGroupWithRank(player, groupId, groupInfo) then
			return true
		end
	end

	return false
end

-- Function to parse duration strings into seconds
local function parseDuration(durationStr)
	local duration = tonumber(durationStr:match("(%d+)"))
	local unit = durationStr:match("(%a+)")

	if not duration or not unit then
		return nil
	end

	if unit == "s" then
		return duration
	elseif unit == "m" then
		return duration * 60
	elseif unit == "h" then
		return duration * 60 * 60
	elseif unit == "d" then
		return duration * 60 * 60 * 24
	else
		return nil
	end
end

-- Function to ban a player with optional duration and reason
local function banPlayer(userId, durationStr, reason)
	local duration = parseDuration(durationStr) or -1  -- Default to permanent ban if duration is not valid

	local success, err = pcall(function()
		local banHistoryPages = Players:GetBanHistoryAsync(userId)

		local config = {
			UserIds = {userId},
			Duration = duration,
			DisplayReason = "You violated community guideline #5",
			PrivateReason = reason or "No reason provided",
			ExcludeAltAccounts = false,
			ApplyToUniverse = true
		}

		Players:BanAsync(config)
	end)

	if not success then
		warn("Failed to ban player:", err)
	end
end

-- Function to unban a player by UserID
local function unbanPlayer(userId, reason)
	local success, err = pcall(function()
		Players:UnbanUserAsync(userId)
	end)

	if success then
		print("Successfully unbanned UserID:", userId, "Reason:", reason)
	else
		warn("Failed to unban UserID:", userId, "-", err)
	end
end

-- Function to get ban history for a player by UserID
local function getBanHistory(userId)
	local success, banHistoryPages = pcall(function()
		return Players:GetBanHistoryAsync(userId)
	end)

	if success then
		local historyMessage = ""
		for _, entry in ipairs(banHistoryPages:GetCurrentPage()) do
			historyMessage = historyMessage .. "\nBan Details:"
			historyMessage = historyMessage .. "\n- Display Reason: " .. entry.DisplayReason
			historyMessage = historyMessage .. "\n- Private Reason: " .. entry.PrivateReason
			historyMessage = historyMessage .. "\n- Start Time: " .. entry.StartTime
			historyMessage = historyMessage .. "\n- Duration: " .. entry.Duration .. " seconds"
			historyMessage = historyMessage .. "\n- Ban in PlaceId: " .. (entry.PlaceId == -1 and "Universe" or tostring(entry.PlaceId))
			historyMessage = historyMessage .. "\n"
		end
		return historyMessage
	else
		return "Failed to retrieve ban history for UserID " .. userId
	end
end

-- Command handling for place owner or group owner to manage bans and view ban history
game.Players.PlayerAdded:Connect(function(player)
	player.Chatted:Connect(function(message)
		if message:sub(1, #prefix) == prefix or message:sub(1, #silentPrefix) == silentPrefix then
			local command = message:sub(#prefix + 1)
			local isSilent = message:sub(1, #silentPrefix) == silentPrefix
			if isSilent then
				command = message:sub(#silentPrefix + 1)
			end

			local function sendMessageToPlayer(player, message)
				player:SendNotification({Title = "Command Result", Text = message, Duration = 5})
			end

			if command:sub(1, 9) == "banhistory" then
				local userId = tonumber(command:sub(11))  -- Extract UserID from command
				if userId then
					-- Check if the player can view ban history
					if canBan(player) then
						local history = getBanHistory(userId)
						sendMessageToPlayer(player, "Ban History for UserID " .. userId .. ":" .. history)
					else
						sendMessageToPlayer(player, "You are not authorized to view ban history.")
					end
				else
					sendMessageToPlayer(player, "Invalid command. Use /banhistory <UserID> to view ban history.")
				end
			elseif command:sub(1, 3) == "ban" then
				local args = command:sub(5):split(" ")  -- Extract UserID, Duration, and Reason from command
				local userId = tonumber(args[1])
				local durationStr = args[2]
				local reason = table.concat(args, " ", 3) or "No reason provided"
				if userId then
					-- Check if the player can ban
					if canBan(player) then
						if userId < 0 and not RunService:IsStudio() then
							sendMessageToPlayer(player, "You cannot ban special UserIDs in production.")
						else
							banPlayer(userId, durationStr, reason)
							sendMessageToPlayer(player, "Successfully banned UserID " .. userId .. " for reason: " .. reason)
						end
					else
						sendMessageToPlayer(player, "You are not authorized to ban players.")
					end
				else
					sendMessageToPlayer(player, "Invalid command. Use /ban <UserID> <Duration> <Reason> to ban a player.")
				end
			elseif command:sub(1, 5) == "unban" then
				local args = command:sub(7):split(" ")  -- Extract UserID and Reason from command
				local userId = tonumber(args[1])
				local reason = table.concat(args, " ", 2) or "No reason provided"
				if userId then
					-- Check if the player can unban
					if canUnban(player) then
						unbanPlayer(userId, reason)
						sendMessageToPlayer(player, "Successfully unbanned UserID " .. userId .. " for reason: " .. reason)
					else
						sendMessageToPlayer(player, "You are not authorized to unban players.")
					end
				else
					sendMessageToPlayer(player, "Invalid command. Use /unban <UserID> <Reason> to unban a player.")
				end
			end
		end
	end)
end)
17 Likes

Amazing, thank you so much for this Roblox! It was definitely a good and long needed feature, especially the alt detection that we as developers haven’t been able to do by our selves due to the permission restrictions (which couldn’t have been lifted since it would make for privacy issues instead).

Let’s just hope the alt-detection system does a good job of detecting alts :slight_smile:

3 Likes

Summer 2022 me would be jumping around the room and screaming like a little girl, and even right now I have a HUGE smile on my face. Awesome work! I’m so happy this is finally here, great updates so far in 2024! :partying_face:

3 Likes

I didn’t get to try since I managed to get my main unbanned through my alt, but I’ll be sure to give it a try the next time I play around with the ban system.

2 Likes

It didn’t work when I tried using it on two separate alt accounts

4 Likes

oh my god its happening, everybody calm down, its actually happening, its been years and years of making our own ban systems but now, we finally have got a API for bans, amazing work, this is a long needed addition finally being implemented, the day is here coders of roblox, lets hope it works well and takes out them alts

4 Likes

In creative spaces, the issue isn’t AI period, it’s generative AI. In this case, AI (if being used) is being used as a tool to assist people’s jobs, not stealing ideas from actual humans. AI can be used for good, but because of the general use of it it’s muddied the waters alot.

2 Likes

I tested it, joined on an alt and it did in fact detect it! Wow.

4 Likes

Yay! So excited to revamp my mod commands with this. Thanks for the update

2 Likes

cookies get changed when you log out of your account so probably not

2 Likes

Definitely a L for Roblox. Barneyhunter12 is def never gonna get to troll. Welp. Gotta remind my comrades at BloxStreet.

4 Likes

however I dont truly see any other way of it being used
IPs are too sloppy, a lot of time they’re shared which could lead to other people being wrongfully banned, and HWID’s are spoofable, and could also be bypassed by just… using a different device, I wish they revealed some documentation on this because its an interesting implementation if it actually works reliably

2 Likes

I just hopped in game, opened the server console and used this (dont forget to replace userid):

game:GetService("Players"):BanAsync({UserIds = {248428063}, Duration = 300, DisplayReason = "Im testing lol", PrivateReason = "Testing2"})
4 Likes

Best thing Roblox has done all year hands down this will help so many experiences with exploiter issues.

2 Likes

How did you get it to work? Just logged into your alt?

1 Like

Yeah, I’m logged into a different account on Windows App version of roblox so I just opened that and then played the game and it detected me.

2 Likes

You are probably right in your assumption that they probably use cookies. They have a BrowserID cookie (if I remember correctly), and people that use VPNs or public connections would be screwed over if they used IP addresses.

It’s easy to clear cookies, but I’d rather bad actors who are too unwise to clear their cookies stay banned than having to deal with appeals from innocent players who happened to share the same IP address as a bad actor.

1 Like

I actually believe that might be how it works in some form, I got banned recently for a day on an alt (dont ask) and I closed roblox before logging out, then when i tried to boot up with my main I ran into an error message, it was only until I cleared my cache i was able to play again.

Bug or leaked new feature, call it.

2 Likes