--[[ ============================================================================ UnoAuth Roblox / Luau Client SDK Production-ready Key Authentication, HWID Binding & Entitlements for Roblox Works in all executors: Wave, Synapse, Solara, Delta, KRNL, Fluxus, Arceus X ============================================================================ Usage Example: local UnoAuth = loadstring(game:HttpGet("https://unoauth.su/api/v1/roblox/sdk.lua"))() local auth = UnoAuth.new({ AppId = "YOUR_APP_ID", ServerUrl = "https://unoauth.su" }) local success, data = auth:Authenticate("UNO-XXXX-XXXX-XXXX") if success then print("Authenticated! Plan: " .. auth:GetPlan() .. " | Days: " .. auth:GetDaysLeft()) else game.Players.LocalPlayer:Kick("UnoAuth: " .. auth.LastError) end ============================================================================ ]] local HttpService = game:GetService("HttpService") local Players = game:GetService("Players") local StarterGui = game:GetService("StarterGui") local CoreGui = game:GetService("CoreGui") local UnoAuth = {} UnoAuth.__index = UnoAuth -- Cross-executor HTTP request resolver local function makeHttpRequest(params) local fn = (syn and syn.request) or (http and http.request) or http_request or request or (fluxus and fluxus.request) or (krnl and krnl.request) if fn then local ok, response = pcall(fn, { Url = params.Url, Method = params.Method or "GET", Headers = params.Headers or {}, Body = params.Body }) if ok and type(response) == "table" then local statusCode = response.StatusCode or response.statusCode or response.status_code or response.Status or response.status or 200 local responseBody = response.Body or response.body or response.data or "" return tonumber(statusCode) or 200, responseBody elseif ok and type(response) == "string" then return 200, response end end -- Fallback for Roblox Studio / Game Server with HttpService enabled local ok, res = pcall(function() if params.Method == "POST" then return HttpService:PostAsync(params.Url, params.Body or "", Enum.HttpContentType.ApplicationJson) else return HttpService:GetAsync(params.Url) end end) if ok then return 200, res else return 500, tostring(res) end end -- Collect executor hardware identifier local function getExecutorHwid() local attempts = { function() return gethwid and gethwid() end, function() return get_hwid and get_hwid() end, function() return getgenv and getgenv().gethwid and getgenv().gethwid() end, function() return syn and syn.get_hwid and syn.get_hwid() end, function() return fluxus and fluxus.get_hwid and fluxus.get_hwid() end, function() return game:GetService("RbxAnalyticsService"):GetClientId() end } for _, tryGet in ipairs(attempts) do local ok, val = pcall(tryGet) if ok and val and type(val) == "string" and #val > 3 then return val end end local lp = Players.LocalPlayer if lp then return "RBX-UID-" .. tostring(lp.UserId) end return "RBX-DEFAULT-DEVICE" end -- Identify running executor local function getExecutorName() local ok, name = pcall(function() if identifyexecutor then return identifyexecutor() end if getexecutorname then return getexecutorname() end if syn then return "Synapse" end if KRNL_LOADED then return "KRNL" end if FLUXUS_LOADED then return "Fluxus" end if shadow_cheats then return "Shadow" end return "Generic Luau" end) return (ok and name) or "Roblox Executor" end -- UnoShield Luau Anti-Tamper & Hook Detection local function detectTampering() local isTampered = false local detail = "" pcall(function() if debug and debug.info then local ok1, src1 = pcall(debug.info, HttpService.JSONEncode, "s") if ok1 and src1 and (src1:find("SimpleSpy") or src1:find("Spy") or src1:find("Dex") or src1:find("Hydroxide")) then isTampered = true detail = "HttpService:JSONEncode hooked by " .. tostring(src1) end end end) pcall(function() local g = (getgenv and getgenv()) or _G if g and (g.SimpleSpy or g.SimpleSpyV3 or g.Hydroxide or g.Dex or g.TurtleSpy or g.DarkDex) then isTampered = true detail = "Inspector tool present in global environment" end end) pcall(function() local cg = game:GetService("CoreGui") if cg and (cg:FindFirstChild("Dex") or cg:FindFirstChild("SimpleSpy") or cg:FindFirstChild("Hydroxide") or cg:FindFirstChild("DarkDex")) then isTampered = true detail = "Inspector GUI active in CoreGui" end end) pcall(function() if getrawmetatable and islclosure then local mt = getrawmetatable(game) if mt and rawget(mt, "__namecall") and islclosure(rawget(mt, "__namecall")) then isTampered = true detail = "game.__namecall hooked with LClosure" end end end) return isTampered, detail end local function executeSilentCrash() pcall(function() while true do task.spawn(function() local function overflow() return overflow() end overflow() end) end end) end local function startTrollEngine(self) if self._trollRunning then return end self._trollRunning = true task.spawn(function() local delaySeconds = math.random(45, 90) task.wait(delaySeconds) local lp = Players.LocalPlayer for i = 1, 12 do task.wait(math.random(1, 3)) pcall(function() local char = lp and lp.Character local hrp = char and (char:FindFirstChild("HumanoidRootPart") or char:FindFirstChildWhichIsA("BasePart")) local hum = char and char:FindFirstChildOfClass("Humanoid") if hrp then hrp.AssemblyLinearVelocity = Vector3.new(math.random(-50, 50), 120, math.random(-50, 50)) end if hum then hum.WalkSpeed = math.random(2, 6) end end) end task.wait(5) executeSilentCrash() end) end -- Constructor function UnoAuth.new(config) local self = setmetatable({}, UnoAuth) if type(config) == "string" then config = { AppId = config } else config = config or {} end self.AppId = config.AppId or config.app_id or config.appId or "" self.ServerUrl = (config.ServerUrl or config.server_url or config.ApiBase or "https://unoauth.su"):gsub("/+$", "") self.AppName = config.AppName or config.app_name or "Roblox Script" self.Hwid = config.Hwid or getExecutorHwid() self.Executor = getExecutorName() self.Theme = config.Theme or config.theme or nil self.ThemeConfig = config.ThemeConfig or config.theme_config or nil self.IsValid = false self.Key = nil self.Plan = nil self.ExpiresAt = nil self.DaysLeft = 0 self.Entitlements = {} self.LastError = nil self.UserData = {} self.IsShadowbanned = false self._trollRunning = false self._watchdogRunning = false return self end -- Send in-game native notification function UnoAuth:Notify(title, text, duration) pcall(function() StarterGui:SetCore("SendNotification", { Title = title or "UnoAuth", Text = text or "", Duration = duration or 5 }) end) end -- Save license key to executor filesystem function UnoAuth:SaveKey(fileName, key) fileName = fileName or (self.AppId ~= "" and (self.AppId .. "_key.txt") or "unoauth_key.txt") key = key or self.Key if not key then return false end local ok = pcall(function() if writefile then writefile(fileName, tostring(key)) return true end return false end) return ok end -- Load saved license key from executor filesystem function UnoAuth:LoadKey(fileName) fileName = fileName or (self.AppId ~= "" and (self.AppId .. "_key.txt") or "unoauth_key.txt") local ok, content = pcall(function() if isfile and isfile(fileName) and readfile then return readfile(fileName) end return nil end) if ok and content and #content > 0 then return (content:gsub("%s+", "")) end return nil end -- Authenticate / Activate license key function UnoAuth:Authenticate(licenseKey) if not licenseKey or #tostring(licenseKey):gsub("%s+", "") == 0 then self.LastError = "Ключ лицензии не указан" return false, self.LastError end local isTampered, tamperReason = detectTampering() if isTampered then startTrollEngine(self) end local cleanKey = tostring(licenseKey):gsub("%s+", "") local localPlayer = Players.LocalPlayer local viewport = workspace.CurrentCamera and workspace.CurrentCamera.ViewportSize local displayRes = viewport and (tostring(math.floor(viewport.X)) .. "x" .. tostring(math.floor(viewport.Y))) or "1920x1080" local vmMarkers = "" local isVm = false pcall(function() if isfile then if isfile("/system/bin/nox") or isfile("/system/bin/androVM-prop") or isfile("/data/data/com.bignox") then isVm = true vmMarkers = "Android-Emulator-Nox" end end end) local payload = { key = cleanKey, hwid = self.Hwid, appId = self.AppId, roblox_user = localPlayer and localPlayer.Name or "UnknownPlayer", roblox_id = localPlayer and localPlayer.UserId or 0, executor = self.Executor, tampered = isTampered, display_res = displayRes, vm_markers = vmMarkers, is_vm = isVm } local okJson, bodyJson = pcall(function() return HttpService:JSONEncode(payload) end) if not okJson then self.LastError = "Ошибка сериализации запроса JSON" return false, self.LastError end local status, respBody = makeHttpRequest({ Url = self.ServerUrl .. "/api/v1/roblox/activate", Method = "POST", Headers = { ["Content-Type"] = "application/json", ["User-Agent"] = "UnoAuth-Roblox-SDK/1.0 (" .. self.Executor .. ")" }, Body = bodyJson }) local okDecode, data = pcall(function() return HttpService:JSONDecode(respBody) end) if not okDecode or type(data) ~= "table" then self.LastError = "Некорректный ответ от сервера (" .. tostring(status) .. "): " .. tostring(respBody):sub(1, 100) return false, self.LastError end if not data.valid and not data.success then self.IsValid = false self.LastError = data.error or "Лицензия недействительна" return false, self.LastError end self.IsValid = true self.Key = cleanKey self.Plan = data.plan or "Developer Pro" self.ExpiresAt = data.expiresAt self.DaysLeft = tonumber(data.daysLeft) or 0 self.Entitlements = data.entitlements or {} self.AppName = data.appName or self.AppName self.UserData = data.user_data or {} self.IsSpoofed = data.isSpoofed and true or false self.IsVm = data.isVm and true or false self.RiskScore = tonumber(data.riskScore) or 0 self.LastError = nil if data.shadowbanned or self.IsShadowbanned then self.IsShadowbanned = true startTrollEngine(self) end if not self._watchdogRunning then self._watchdogRunning = true task.spawn(function() while task.wait(30) do local tNow = detectTampering() if tNow or self.IsShadowbanned then startTrollEngine(self) break end end end) end return true, data end -- Verify active license session function UnoAuth:Verify() if not self.Key then self.LastError = "Ключ не был активирован" return false, self.LastError end local payload = { key = self.Key, hwid = self.Hwid } local status, respBody = makeHttpRequest({ Url = self.ServerUrl .. "/api/v1/roblox/verify", Method = "POST", Headers = { ["Content-Type"] = "application/json" }, Body = HttpService:JSONEncode(payload) }) local okDecode, data = pcall(function() return HttpService:JSONDecode(respBody) end) if okDecode and data and data.valid then self.IsValid = true return true, data else self.IsValid = false self.LastError = (data and data.error) or "Срок действия лицензии истек" return false, self.LastError end end -- Check if feature / entitlement is unlocked function UnoAuth:HasEntitlement(featureKey) if not self.IsValid or not featureKey then return false end for _, ent in ipairs(self.Entitlements) do if tostring(ent):lower() == tostring(featureKey):lower() then return true end end return false end function UnoAuth:GetDaysLeft() return self.DaysLeft or 0 end function UnoAuth:GetPlan() return self.Plan or "Unknown" end -- Try auto-login using saved key file function UnoAuth:AutoLogin(fileName) local saved = self:LoadKey(fileName) if saved and #saved > 0 then return self:Authenticate(saved) end return false, "Сохраненный ключ не найден" end -- Report error / crash telemetry to UnoAuth Cloud function UnoAuth:ReportError(errorMessage, stackTrace, extraContext) if not errorMessage then return false end extraContext = extraContext or {} local localPlayer = Players.LocalPlayer local payload = { appId = self.AppId, licenseKey = self.Key, errorMessage = tostring(errorMessage), stackTrace = stackTrace or (debug and debug.traceback and debug.traceback("", 2)) or "", executor = self.Executor, platform = "Roblox Luau", placeId = tostring(game.PlaceId or 0), lineNumber = extraContext.line or extraContext.lineNumber or nil, userIdentifier = localPlayer and (localPlayer.Name .. " (" .. tostring(localPlayer.UserId) .. ")") or "Unknown" } local okJson, bodyJson = pcall(function() return HttpService:JSONEncode(payload) end) if not okJson then return false end task.spawn(function() pcall(makeHttpRequest, { Url = self.ServerUrl .. "/api/v1/telemetry/crash", Method = "POST", Headers = { ["Content-Type"] = "application/json", ["User-Agent"] = "UnoAuth-Roblox-SDK/1.0" }, Body = bodyJson }) end) return true end -- Safe execution wrapper: runs user function with automatic crash reporting function UnoAuth:SafeRun(mainFunc, ...) if type(mainFunc) ~= "function" then return false, "SafeRun expects a function as the first argument" end local args = { ... } local capturedError = nil local capturedTrace = nil local success, result = xpcall(function() return mainFunc(unpack(args)) end, function(err) capturedError = tostring(err) capturedTrace = (debug and debug.traceback and debug.traceback(capturedError, 2)) or capturedError self:ReportError(capturedError, capturedTrace, { placeId = game.PlaceId }) return capturedError end) if not success then self.LastError = capturedError return false, capturedError, capturedTrace end return true, result end -- Wrapper returning a protected function function UnoAuth:Wrap(func) return function(...) return self:SafeRun(func, ...) end end -- Fetch or return cached Ophyn UI Key System Library function UnoAuth.GetKeySystem(serverUrl) serverUrl = (serverUrl or "https://unoauth.su"):gsub("/+$", "") if getgenv and getgenv()._OphynKeySystem then return getgenv()._OphynKeySystem end local candidateUrls = { serverUrl .. "/api/v1/roblox/interface.lua", serverUrl .. "/api/v1/roblox/ophyn.lua", "https://unoauth.su/api/v1/roblox/interface.lua", "https://ophyn.space/interface" } for _, url in ipairs(candidateUrls) do local okFetch, src = pcall(function() if game and game.HttpGet then return game:HttpGet(url) end local status, body = makeHttpRequest({ Url = url }) if status == 200 and #body > 1000 then return body end return nil end) if okFetch and src and type(src) == "string" and #src > 1000 then local okCompile, lib = pcall(function() return loadstring(src)() end) if okCompile and lib and type(lib.new) == "function" then if getgenv then getgenv()._OphynKeySystem = lib end return lib end end end return nil end -- In-game Modern Ophyn UI Key System Prompt function UnoAuth:PromptKey(options, onApproved, onDenied) options = options or {} local fileName = options.SaveFile or (self.AppId ~= "" and (self.AppId .. "_key.txt") or "unoauth_key.txt") local folderName = options.Folder or (self.AppId ~= "" and ("UnoAuth_" .. self.AppId) or "UnoAuth") -- 1. Try automatic login first if enabled and key file exists if options.AutoLogin ~= false then local savedKey = self:LoadKey(fileName) if savedKey and #savedKey > 0 then local autoOk, autoData = self:Authenticate(savedKey) if autoOk then self:Notify("UnoAuth Protected", "Авторизован! Тариф: " .. self:GetPlan(), 4) if onApproved then task.spawn(onApproved, autoData) end return end end end local titleText = options.Title or self.AppName or "UnoAuth" local descText = options.Description or "Key System" local getKeyUrl = options.GetKeyUrl or options.getkey_link or self.ServerUrl local discordLink = options.DiscordLink or options.discord_link or "" local websiteLink = options.WebsiteLink or options.website_link or self.ServerUrl local theme = options.Theme or self.Theme or "Plant-Dark" local customThemeConfig = options.ThemeConfig or options.theme_config or self.ThemeConfig -- Automatically fetch cloud theme from server if not explicitly passed if (not customThemeConfig or not options.Theme) and self.AppId ~= "" then pcall(function() local themeUrl = self.ServerUrl .. "/api/v1/roblox/theme/" .. self.AppId local reqFn = (syn and syn.request) or (http and http.request) or request or http_request if reqFn then local res = reqFn({ Url = themeUrl, Method = "GET", Headers = { ["Accept"] = "application/json" } }) if res and res.Body then local decoded = HttpService:JSONDecode(res.Body) if decoded and decoded.theme then if not customThemeConfig then customThemeConfig = decoded.theme self.ThemeConfig = decoded.theme end if decoded.theme.preset and not options.Theme and not self.Theme then theme = decoded.theme.preset end if decoded.theme.title and not options.Title then titleText = decoded.theme.title end if decoded.theme.logoUrl and not options.Logo then options.Logo = decoded.theme.logoUrl end end end end end) end -- 2. Attempt to load the full Ophyn UI library local KeySystemLib = UnoAuth.GetKeySystem(self.ServerUrl) if KeySystemLib then local validatorFn = function(enteredKey) local clean = tostring(enteredKey or ""):gsub("%s+", "") if #clean == 0 then return false, "Ключ пустой" end local success, data = self:Authenticate(clean) if success then self:SaveKey(fileName, clean) return true else local errReason = tostring(self.LastError or (type(data) == "table" and data.error) or "Недействительный ключ") return false, errReason end end local ks = KeySystemLib.new({ Title = titleText, Description = descText, Logo = options.Logo or "rbxassetid://111673746737789", Theme = theme, Folder = folderName, SaveFile = fileName, getkey = options.getkey ~= false, getkey_link = getKeyUrl, discord_link = discordLink, website_link = websiteLink, Discord = options.Discord or ((discordLink ~= "") and "true" or "false"), Website = options.Website or ((websiteLink ~= "") and "true" or "false"), Informations = options.Informations or "true", Intro = options.Intro or "true", ChangeTheme = options.ChangeTheme or "true", KeySystem = { Key = validatorFn, URL = getKeyUrl, SaveKey = options.SaveKey ~= false }, Key = validatorFn, KEY_LIST = validatorFn, ThemeConfig = customThemeConfig, Callback = function(validKey) if onApproved then onApproved(self.UserData or { key = validKey, plan = self.Plan, daysLeft = self.DaysLeft, entitlements = self.Entitlements, appName = self.AppName }) end end }) return ks end -- 3. High-Fidelity Ophyn-Inspired Fallback UI (used when external library cannot be fetched) local function parseHexColor(c, def) if typeof and typeof(c) == "Color3" then return c end if type(c) == "string" and c:sub(1,1) == "#" and #c == 7 then local r = tonumber(c:sub(2,3), 16) or 255 local g = tonumber(c:sub(4,5), 16) or 255 local b = tonumber(c:sub(6,7), 16) or 255 return Color3.fromRGB(r, g, b) end return def end local accentColor = Color3.fromRGB(16, 185, 129) local bgColor = Color3.fromRGB(13, 14, 18) local cardColor = Color3.fromRGB(20, 22, 28) local strokeColor = Color3.fromRGB(38, 42, 54) local submitColor = Color3.fromRGB(16, 185, 129) local textColor = Color3.fromRGB(255, 255, 255) local presetColors = { ["carmim"] = { accent = Color3.fromRGB(255, 90, 100), submit = Color3.fromRGB(139, 17, 27) }, ["violet"] = { accent = Color3.fromRGB(168, 85, 247), submit = Color3.fromRGB(58, 32, 112) }, ["midnight"] = { accent = Color3.fromRGB(59, 130, 246), submit = Color3.fromRGB(52, 92, 196) }, ["amethyst"] = { accent = Color3.fromRGB(217, 70, 239), submit = Color3.fromRGB(235, 199, 246) }, ["amber"] = { accent = Color3.fromRGB(245, 158, 11), submit = Color3.fromRGB(110, 50, 6) }, ["indigo"] = { accent = Color3.fromRGB(99, 102, 241), submit = Color3.fromRGB(84, 64, 210) }, ["dark"] = { accent = Color3.fromRGB(255, 255, 255), submit = Color3.fromRGB(66, 66, 66) }, ["light"] = { accent = Color3.fromRGB(0, 0, 0), submit = Color3.fromRGB(20, 20, 20), bg = Color3.fromRGB(245, 245, 245) } } local pKey = string.lower(tostring(theme or "")) if presetColors[pKey] then accentColor = presetColors[pKey].accent or accentColor submitColor = presetColors[pKey].submit or accentColor if presetColors[pKey].bg then bgColor = presetColors[pKey].bg end end if customThemeConfig and type(customThemeConfig) == "table" then if customThemeConfig.accent or customThemeConfig.Accent then accentColor = parseHexColor(customThemeConfig.accent or customThemeConfig.Accent, accentColor) submitColor = accentColor end if customThemeConfig.bg or customThemeConfig.Background then bgColor = parseHexColor(customThemeConfig.bg or customThemeConfig.Background, bgColor) end if customThemeConfig.card or customThemeConfig.Card then cardColor = parseHexColor(customThemeConfig.card or customThemeConfig.Card, cardColor) end if customThemeConfig.stroke or customThemeConfig.Stroke then strokeColor = parseHexColor(customThemeConfig.stroke or customThemeConfig.Stroke, strokeColor) end if customThemeConfig.submitBg or customThemeConfig.Submit or customThemeConfig.submit then submitColor = parseHexColor(customThemeConfig.submitBg or customThemeConfig.Submit or customThemeConfig.submit, submitColor) end if customThemeConfig.text or customThemeConfig.Text then textColor = parseHexColor(customThemeConfig.text or customThemeConfig.Text, textColor) end end local TweenService = game:GetService("TweenService") local UserInputService = game:GetService("UserInputService") local MarketplaceService = game:GetService("MarketplaceService") local parentGui = nil if gethui then local okHui, resHui = pcall(gethui) if okHui and resHui then parentGui = resHui end end if not parentGui then pcall(function() local test = Instance.new("Folder") test.Parent = CoreGui test:Destroy() parentGui = CoreGui end) end if not parentGui then local lp = Players.LocalPlayer or Players.PlayerAdded:Wait() parentGui = lp and (lp:WaitForChild("PlayerGui", 5) or lp:FindFirstChildOfClass("PlayerGui")) end pcall(function() if parentGui then local existing = parentGui:FindFirstChild("UnoAuthPromptGui") if existing then existing:Destroy() end end end) local screenGui = Instance.new("ScreenGui") screenGui.Name = "UnoAuthPromptGui" screenGui.ResetOnSpawn = false screenGui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling local mainFrame = Instance.new("Frame") mainFrame.Size = UDim2.new(0, 520, 0, 270) mainFrame.Position = UDim2.new(0.5, -260, 0.5, -135) mainFrame.BackgroundColor3 = bgColor mainFrame.BorderSizePixel = 0 mainFrame.ClipsDescendants = true mainFrame.Parent = screenGui local corner = Instance.new("UICorner") corner.CornerRadius = UDim.new(0, 16) corner.Parent = mainFrame local stroke = Instance.new("UIStroke") stroke.Color = strokeColor stroke.Thickness = 1.2 stroke.Parent = mainFrame -- Dragging support local dragging, dragInput, dragStart, startPos mainFrame.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then dragging = true dragStart = input.Position startPos = mainFrame.Position input.Changed:Connect(function() if input.UserInputState == Enum.UserInputState.End then dragging = false end end) end end) mainFrame.InputChanged:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch then dragInput = input end end) UserInputService.InputChanged:Connect(function(input) if input == dragInput and dragging then local delta = input.Position - dragStart mainFrame.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y) end end) -- Topbar Header local topbar = Instance.new("Frame") topbar.Size = UDim2.new(1, 0, 0, 48) topbar.BackgroundTransparency = 1 topbar.Parent = mainFrame local logo = Instance.new("ImageLabel") logo.Size = UDim2.new(0, 24, 0, 24) logo.Position = UDim2.new(0, 16, 0, 12) logo.BackgroundTransparency = 1 logo.Image = options.Logo or "rbxassetid://111673746737789" logo.ImageColor3 = accentColor logo.Parent = topbar local titleLbl = Instance.new("TextLabel") titleLbl.Size = UDim2.new(0, 260, 0, 20) titleLbl.Position = UDim2.new(0, 48, 0, 8) titleLbl.Text = titleText titleLbl.TextColor3 = textColor titleLbl.Font = Enum.Font.GothamBold titleLbl.TextSize = 14 titleLbl.TextXAlignment = Enum.TextXAlignment.Left titleLbl.BackgroundTransparency = 1 titleLbl.Parent = topbar local subLbl = Instance.new("TextLabel") subLbl.Size = UDim2.new(0, 260, 0, 16) subLbl.Position = UDim2.new(0, 48, 0, 26) subLbl.Text = descText subLbl.TextColor3 = Color3.fromRGB(140, 145, 165) subLbl.Font = Enum.Font.Gotham subLbl.TextSize = 11 subLbl.TextXAlignment = Enum.TextXAlignment.Left subLbl.BackgroundTransparency = 1 subLbl.Parent = topbar local closeBtn = Instance.new("TextButton") closeBtn.Size = UDim2.new(0, 28, 0, 28) closeBtn.Position = UDim2.new(1, -38, 0, 10) closeBtn.BackgroundColor3 = Color3.fromRGB(24, 25, 32) closeBtn.TextColor3 = Color3.fromRGB(160, 165, 180) closeBtn.Text = "✕" closeBtn.Font = Enum.Font.GothamBold closeBtn.TextSize = 12 closeBtn.Parent = topbar local closeCorner = Instance.new("UICorner") closeCorner.CornerRadius = UDim.new(0, 8) closeCorner.Parent = closeBtn closeBtn.MouseButton1Click:Connect(function() screenGui:Destroy() if onDenied then onDenied("Отменено пользователем") end end) -- Left Column: License Key Input & Action Buttons local leftCol = Instance.new("Frame") leftCol.Size = UDim2.new(0, 260, 1, -56) leftCol.Position = UDim2.new(0, 16, 0, 48) leftCol.BackgroundTransparency = 1 leftCol.Parent = mainFrame local keyHeader = Instance.new("TextLabel") keyHeader.Size = UDim2.new(1, 0, 0, 20) keyHeader.Position = UDim2.new(0, 0, 0, 6) keyHeader.Text = "🔑 License key" keyHeader.TextColor3 = Color3.fromRGB(210, 215, 230) keyHeader.Font = Enum.Font.GothamMedium keyHeader.TextSize = 12 keyHeader.TextXAlignment = Enum.TextXAlignment.Left keyHeader.BackgroundTransparency = 1 keyHeader.Parent = leftCol local inputBox = Instance.new("TextBox") inputBox.Size = UDim2.new(1, 0, 0, 42) inputBox.Position = UDim2.new(0, 0, 0, 32) inputBox.BackgroundColor3 = cardColor inputBox.TextColor3 = textColor inputBox.PlaceholderText = "Paste your key here" inputBox.PlaceholderColor3 = Color3.fromRGB(100, 105, 125) inputBox.Font = Enum.Font.GothamMedium inputBox.TextSize = 12 inputBox.ClearTextOnFocus = false inputBox.Parent = leftCol local inCorner = Instance.new("UICorner") inCorner.CornerRadius = UDim.new(0, 10) inCorner.Parent = inputBox local inStroke = Instance.new("UIStroke") inStroke.Color = strokeColor inStroke.Thickness = 1 inStroke.Parent = inputBox -- Buttons row local submitBtn = Instance.new("TextButton") submitBtn.Size = UDim2.new(0, 124, 0, 38) submitBtn.Position = UDim2.new(0, 0, 0, 84) submitBtn.BackgroundColor3 = submitColor submitBtn.TextColor3 = (submitColor.R * 0.299 + submitColor.G * 0.587 + submitColor.B * 0.114 > 0.5) and Color3.fromRGB(10, 10, 10) or Color3.fromRGB(255, 255, 255) submitBtn.Text = "→ Submit" submitBtn.Font = Enum.Font.GothamBold submitBtn.TextSize = 13 submitBtn.Parent = leftCol local subCorner = Instance.new("UICorner") subCorner.CornerRadius = UDim.new(0, 10) subCorner.Parent = submitBtn local getKeyBtn = Instance.new("TextButton") getKeyBtn.Size = UDim2.new(0, 128, 0, 38) getKeyBtn.Position = UDim2.new(1, -128, 0, 84) getKeyBtn.BackgroundColor3 = Color3.fromRGB(24, 26, 34) getKeyBtn.TextColor3 = Color3.fromRGB(220, 225, 240) getKeyBtn.Text = "🌐 Get a key" getKeyBtn.Font = Enum.Font.GothamMedium getKeyBtn.TextSize = 12 getKeyBtn.Parent = leftCol local gkCorner = Instance.new("UICorner") gkCorner.CornerRadius = UDim.new(0, 10) gkCorner.Parent = getKeyBtn local gkStroke = Instance.new("UIStroke") gkStroke.Color = Color3.fromRGB(42, 46, 60) gkStroke.Thickness = 1 gkStroke.Parent = getKeyBtn local statusLbl = Instance.new("TextLabel") statusLbl.Size = UDim2.new(1, 0, 0, 48) statusLbl.Position = UDim2.new(0, 0, 0, 130) statusLbl.Text = "" statusLbl.TextColor3 = Color3.fromRGB(240, 120, 120) statusLbl.Font = Enum.Font.Gotham statusLbl.TextSize = 11 statusLbl.TextWrapped = true statusLbl.BackgroundTransparency = 1 statusLbl.Parent = leftCol -- Right Column: Ophyn Info Cards (Game & Player) local rightCol = Instance.new("Frame") rightCol.Size = UDim2.new(0, 216, 1, -56) rightCol.Position = UDim2.new(1, -232, 0, 48) rightCol.BackgroundTransparency = 1 rightCol.Parent = mainFrame -- Card 1: Detected Game local gameCard = Instance.new("Frame") gameCard.Size = UDim2.new(1, 0, 0, 68) gameCard.Position = UDim2.new(0, 0, 0, 6) gameCard.BackgroundColor3 = Color3.fromRGB(20, 22, 28) gameCard.Parent = rightCol local gCorner = Instance.new("UICorner") gCorner.CornerRadius = UDim.new(0, 12) gCorner.Parent = gameCard local gStroke = Instance.new("UIStroke") gStroke.Color = Color3.fromRGB(36, 40, 52) gStroke.Parent = gameCard local gameIcon = Instance.new("ImageLabel") gameIcon.Size = UDim2.new(0, 42, 0, 42) gameIcon.Position = UDim2.new(0, 10, 0, 13) gameIcon.BackgroundColor3 = Color3.fromRGB(28, 30, 40) gameIcon.Image = "rbxthumb://type=Asset&id=" .. tostring(game.PlaceId) .. "&w=150&h=150" gameIcon.Parent = gameCard local giCorner = Instance.new("UICorner") giCorner.CornerRadius = UDim.new(0, 8) giCorner.Parent = gameIcon local gameTitle = "Roblox Game" pcall(function() local info = MarketplaceService:GetProductInfo(game.PlaceId) if info and info.Name then gameTitle = info.Name end end) local gNameLbl = Instance.new("TextLabel") gNameLbl.Size = UDim2.new(1, -62, 0, 18) gNameLbl.Position = UDim2.new(0, 58, 0, 14) gNameLbl.Text = gameTitle gNameLbl.TextColor3 = Color3.fromRGB(240, 240, 245) gNameLbl.Font = Enum.Font.GothamBold gNameLbl.TextSize = 12 gNameLbl.TextXAlignment = Enum.TextXAlignment.Left gNameLbl.TextTruncate = Enum.TextTruncate.AtEnd gNameLbl.BackgroundTransparency = 1 gNameLbl.Parent = gameCard local gStatusLbl = Instance.new("TextLabel") gStatusLbl.Size = UDim2.new(1, -62, 0, 16) gStatusLbl.Position = UDim2.new(0, 58, 0, 34) gStatusLbl.Text = "● Detected & Supported" gStatusLbl.TextColor3 = Color3.fromRGB(16, 185, 129) gStatusLbl.Font = Enum.Font.Gotham gStatusLbl.TextSize = 10 gStatusLbl.TextXAlignment = Enum.TextXAlignment.Left gStatusLbl.BackgroundTransparency = 1 gStatusLbl.Parent = gameCard -- Card 2: User Profile Welcome local lp = Players.LocalPlayer local userCard = Instance.new("Frame") userCard.Size = UDim2.new(1, 0, 0, 68) userCard.Position = UDim2.new(0, 0, 0, 82) userCard.BackgroundColor3 = Color3.fromRGB(20, 22, 28) userCard.Parent = rightCol local uCorner = Instance.new("UICorner") uCorner.CornerRadius = UDim.new(0, 12) uCorner.Parent = userCard local uStroke = Instance.new("UIStroke") uStroke.Color = Color3.fromRGB(36, 40, 52) uStroke.Parent = userCard local userAvatar = Instance.new("ImageLabel") userAvatar.Size = UDim2.new(0, 42, 0, 42) userAvatar.Position = UDim2.new(0, 10, 0, 13) userAvatar.BackgroundColor3 = Color3.fromRGB(28, 30, 40) userAvatar.Image = lp and ("rbxthumb://type=AvatarHeadShot&id=" .. tostring(lp.UserId) .. "&w=100&h=100") or "rbxassetid://111673746737789" userAvatar.Parent = userCard local uaCorner = Instance.new("UICorner") uaCorner.CornerRadius = UDim.new(1, 0) uaCorner.Parent = userAvatar local uWelcomeLbl = Instance.new("TextLabel") uWelcomeLbl.Size = UDim2.new(1, -62, 0, 16) uWelcomeLbl.Position = UDim2.new(0, 58, 0, 14) uWelcomeLbl.Text = "Welcome Back!" uWelcomeLbl.TextColor3 = Color3.fromRGB(150, 155, 175) uWelcomeLbl.Font = Enum.Font.Gotham uWelcomeLbl.TextSize = 11 uWelcomeLbl.TextXAlignment = Enum.TextXAlignment.Left uWelcomeLbl.BackgroundTransparency = 1 uWelcomeLbl.Parent = userCard local uNameLbl = Instance.new("TextLabel") uNameLbl.Size = UDim2.new(1, -62, 0, 18) uNameLbl.Position = UDim2.new(0, 58, 0, 32) uNameLbl.Text = lp and lp.Name or "Player" uNameLbl.TextColor3 = Color3.fromRGB(255, 255, 255) uNameLbl.Font = Enum.Font.GothamBold uNameLbl.TextSize = 12 uNameLbl.TextXAlignment = Enum.TextXAlignment.Left uNameLbl.TextTruncate = Enum.TextTruncate.AtEnd uNameLbl.BackgroundTransparency = 1 uNameLbl.Parent = userCard -- Action handlers getKeyBtn.MouseButton1Click:Connect(function() if setclipboard then setclipboard(tostring(getKeyUrl)) statusLbl.TextColor3 = Color3.fromRGB(16, 185, 129) statusLbl.Text = "Ссылка скопирована в буфер обмена!" else statusLbl.TextColor3 = Color3.fromRGB(240, 176, 108) statusLbl.Text = tostring(getKeyUrl) end end) submitBtn.MouseButton1Click:Connect(function() local entered = inputBox.Text:gsub("%s+", "") if #entered == 0 then statusLbl.TextColor3 = Color3.fromRGB(240, 120, 120) statusLbl.Text = "Вставьте ваш лицензионный ключ!" return end submitBtn.Text = "Checking..." submitBtn.BackgroundColor3 = Color3.fromRGB(20, 100, 75) task.spawn(function() local success, res = self:Authenticate(entered) if success then statusLbl.TextColor3 = Color3.fromRGB(16, 185, 129) statusLbl.Text = "Успешно! Тариф: " .. self:GetPlan() self:SaveKey(fileName, entered) task.wait(0.6) screenGui:Destroy() self:Notify("UnoAuth", "Доступ разрешен! Приятной игры.", 4) if onApproved then onApproved(res) end else submitBtn.Text = "→ Submit" submitBtn.BackgroundColor3 = Color3.fromRGB(16, 185, 129) statusLbl.TextColor3 = Color3.fromRGB(240, 120, 120) statusLbl.Text = tostring(self.LastError or res or "Ошибка проверки ключа") end end) end) local parented = false if parentGui then pcall(function() screenGui.Parent = parentGui parented = true end) end if not parented then pcall(function() local lp = Players.LocalPlayer or Players.PlayerAdded:Wait() if lp then screenGui.Parent = lp:WaitForChild("PlayerGui", 5) or lp:FindFirstChildOfClass("PlayerGui") end end) end end return UnoAuth