Draft preview · this lesson is still being technically validated. Browser experiments and reference material remain available; trusted completion is enabled after publication.
v2 · Activity 3 of 4 · input-validation · permission · distance · 28 min Requires Roblox Studio
Type validation is only the first layer. The server maps an allowlisted ID to its own object instead of accepting a client table pretending to be an Instance.
Context validation checks server-owned permission, live character and distance. Never accept a client-supplied isAllowed or position as proof.
Create UseLamp and a server-owned WorkshopLamp. Initialize CanUseWorkshop=true for this practice lab. Accept only main-lamp, a live nearby character within 10 studs, and the server permission; rate-limit to once per second.
Interface: Complete the documented Studio hierarchy and self-check the behavior outside the browser.
| Input | Expected |
|---|
if type(objectId) ~= "string" or objectId ~= "main-lamp" then return end
if player:GetAttribute("CanUseWorkshop") ~= true then return endA narrow ID and a server-owned permission are separate checks. Passing one does not substitute for the other.
New syntax: input-validation, permission, distance
Your explanation is a self-check. Exact wording is not automatically graded.
Self-checked Studio exercise. A saved checklist records your own review; no uploaded place file or screenshot is executed here.
Workspace/WorkshopLamp (Part, Anchored=true) ReplicatedStorage/UseLamp (RemoteEvent) ServerScriptService/ValidateLamp (Script, RunContext=Server) StarterPlayer/StarterPlayerScripts/RequestLamp (LocalScript)
Main guided reference implementation; use the hierarchy’s stated Script or ModuleScript type.
local Players = game:GetService("Players")
local lamp = game:GetService("Workspace"):WaitForChild("WorkshopLamp")
local remote = game:GetService("ReplicatedStorage"):WaitForChild("UseLamp")
local nextAllowed = {}
local function initialize(player) player:SetAttribute("CanUseWorkshop", true) end
Players.PlayerAdded:Connect(initialize)
for _, player in ipairs(Players:GetPlayers()) do initialize(player) end
Players.PlayerRemoving:Connect(function(player) nextAllowed[player.UserId] = nil end)
remote.OnServerEvent:Connect(function(player, objectId)
local now = os.clock()
if now < (nextAllowed[player.UserId] or 0) then return end
nextAllowed[player.UserId] = now + 1
if type(objectId) ~= "string" or objectId ~= "main-lamp" then return end
if player:GetAttribute("CanUseWorkshop") ~= true then return end
local character = player.Character
local root = character and character:FindFirstChild("HumanoidRootPart")
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
if not root or not root:IsA("BasePart") or not humanoid or humanoid.Health <= 0 then return end
if (root.Position - lamp.Position).Magnitude > 10 then return end
lamp.Color = Color3.fromRGB(234,120,40)
print("Validated lamp request", player.UserId)
end)Controlled client request; server still validates all meaningful context.
local remote = game:GetService("ReplicatedStorage"):WaitForChild("UseLamp")
local player = game:GetService("Players").LocalPlayer
if not player.Character then player.CharacterAdded:Wait() end
task.wait(2)
remote:FireServer("main-lamp")Reset lamp color between rejection tests so an earlier valid action does not hide a failure.
Character spawning races should reject safely; do not assume the root always exists.
This is a bounded learning lab. It has not been executed in an approved Roblox Studio environment by this website.
A checked checklist records your own review, not automated project competence or a community verification.
Type validation is only the first layer. The server maps an allowlisted ID to its own object instead of accepting a client table pretending to be an Instance.
Context validation checks server-owned permission, live character and distance. Never accept a client-supplied isAllowed or position as proof.
The lamp action is temporary shared presentation, not a reward. A per-player cooldown still bounds repeated work. Production systems need domain-specific ownership and tolerances beyond this one Part example.
Replace this code with the starter? Download your draft to keep a copy.
Edit and run these files in Roblox Studio. This browser has no Roblox services, physics, or replication.
Your output will appear here.
Sign in with RoCreators to save private progress across devices. Community verification is separate.