mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-12 07:04:52 +09:00
The largest source was compat.lua returning the setmetatable call directly, which made emmylua infer the module type from the metatable rather than the LibCompat class, hiding every field from consumers. The remaining fixes are nil guards on gui element and character accesses, type annotations for research_sync's script data and player_auth's rcon arguments, casts where the api's read/write union types are wider than the values at runtime, and scoped diagnostic disables for the vendored json.lua and the version fallback code that touches apis removed from the current typedefs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
223 lines
5.5 KiB
Lua
223 lines
5.5 KiB
Lua
local clusterio_api = require("modules/clusterio/api")
|
|
local compat = require("modules/clusterio/compat")
|
|
local auth = {}
|
|
|
|
local v2_styles = compat.version_ge("2.0.0")
|
|
|
|
--- @param player LuaPlayer
|
|
--- @param url string
|
|
--- @param code string
|
|
local function open_dialog(player, url, code)
|
|
if player.gui.screen.player_auth_dialog then
|
|
player.gui.screen.player_auth_dialog.destroy()
|
|
end
|
|
|
|
local frame = player.gui.screen.add {
|
|
name = "player_auth_dialog",
|
|
type = "frame",
|
|
direction = "vertical",
|
|
}
|
|
|
|
local titlebar = frame.add {
|
|
type = "flow",
|
|
}
|
|
titlebar.drag_target = frame
|
|
|
|
local title = titlebar.add {
|
|
type = "label",
|
|
style = "frame_title",
|
|
caption = "Web Interface Login",
|
|
}
|
|
title.drag_target = frame
|
|
|
|
local filler = titlebar.add {
|
|
type = "empty-widget",
|
|
style = "draggable_space_header",
|
|
}
|
|
filler.style.horizontally_stretchable = true
|
|
filler.style.right_margin = 4
|
|
filler.style.height = 24
|
|
filler.drag_target = frame
|
|
|
|
titlebar.add {
|
|
name = "player_auth_dialog_close_button",
|
|
type = "sprite-button",
|
|
sprite = v2_styles and "utility/close" or "utility/close_white",
|
|
hovered_sprite = "utility/close_black",
|
|
clicked_sprite = "utility/close_black",
|
|
style = "frame_action_button",
|
|
}
|
|
|
|
local content = frame.add {
|
|
name = "player_auth_dialog_content",
|
|
type = "frame",
|
|
direction = "vertical",
|
|
style = "inside_shallow_frame_with_padding",
|
|
}
|
|
content.style.width = 300
|
|
|
|
local p1 = content.add {
|
|
type = "label",
|
|
caption = "Login to the web interface is a 3 step process:",
|
|
}
|
|
p1.style.single_line = false
|
|
p1.style.bottom_margin = 8
|
|
|
|
local p2 = content.add {
|
|
type = "label",
|
|
caption = "1. Open the web interface in a browser, the url to it is shown below:",
|
|
}
|
|
p2.style.single_line = false
|
|
p2.style.bottom_margin = 8
|
|
|
|
local url_textfield = content.add {
|
|
type = "textfield",
|
|
text = url,
|
|
}
|
|
url_textfield.style.bottom_margin = 8
|
|
url_textfield.style.width = 300 - 24
|
|
|
|
local p3 = content.add {
|
|
type = "label",
|
|
caption = "2. Enter the following code into step 2 of the Factorio login:",
|
|
}
|
|
p3.style.single_line = false
|
|
p3.style.bottom_margin = 8
|
|
|
|
local player_code_textfield = content.add {
|
|
type = "textfield",
|
|
text = code,
|
|
}
|
|
player_code_textfield.style.bottom_margin = 8
|
|
player_code_textfield.style.width = 180
|
|
|
|
local p4 = content.add {
|
|
type = "label",
|
|
caption = "3. Enter the code in step 3 of the Factorio login here:"
|
|
}
|
|
p4.style.single_line = false
|
|
p4.style.bottom_margin = 8
|
|
|
|
local verify_code_row = content.add {
|
|
type = "flow",
|
|
}
|
|
local verify_code_input = verify_code_row.add {
|
|
name = "player_auth_verify_code_input",
|
|
type = "textfield",
|
|
}
|
|
verify_code_input.style.bottom_margin = 8
|
|
verify_code_input.style.width = 180
|
|
local verify_code_button = verify_code_row.add {
|
|
name = "player_auth_verify_code_button",
|
|
type = "button",
|
|
style = "green_button",
|
|
sprite = "utility/check_mark",
|
|
caption = "Log in",
|
|
}
|
|
verify_code_button.style.minimal_width = 80
|
|
|
|
frame.force_auto_center()
|
|
player.opened = frame
|
|
end
|
|
|
|
function auth.add_commands()
|
|
commands.add_command("web-login", "Login to the web interface", function(event)
|
|
if event.player_index then
|
|
local player = game.players[event.player_index]
|
|
clusterio_api.send_json("player_auth", {
|
|
type = "open_dialog",
|
|
player = player.name,
|
|
})
|
|
return
|
|
end
|
|
|
|
if event.parameter then
|
|
--- @type string[]
|
|
local args = {}
|
|
for w in string.gmatch(event.parameter, "[^ ]+") do
|
|
args[#args + 1] = w
|
|
end
|
|
if #args < 1 then
|
|
rcon.print("Incorrect number of parameters")
|
|
return
|
|
end
|
|
|
|
local command = table.remove(args, 1)
|
|
if command == "open" then
|
|
if #args ~= 3 then
|
|
rcon.print("Incorrect number of parameters")
|
|
return
|
|
end
|
|
|
|
local player_name, url, code = table.unpack(args)
|
|
local player = game.get_player(player_name)
|
|
if not player then
|
|
rcon.print("Player " .. player_name .. " does not exist")
|
|
return
|
|
end
|
|
|
|
open_dialog(player, url, code)
|
|
|
|
elseif command == "code_set" then
|
|
local player_name = args[1]
|
|
local player = game.get_player(player_name)
|
|
if not player then
|
|
rcon.print("Player " .. player_name .. " does not exist")
|
|
return
|
|
end
|
|
|
|
if player.gui.screen.player_auth_dialog then
|
|
player.gui.screen.player_auth_dialog.destroy()
|
|
end
|
|
|
|
elseif command == "error" then
|
|
local player_name = table.remove(args, 1)
|
|
local player = game.get_player(player_name)
|
|
if not player then
|
|
rcon.print("Player " .. player_name .. " does not exist")
|
|
return
|
|
end
|
|
|
|
player.print("Error: " .. table.concat(args, " "))
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
|
|
auth.events = {}
|
|
|
|
--- @param event EventData.on_gui_click
|
|
auth.events[defines.events.on_gui_click] = function(event)
|
|
if not event.element or not event.element.valid then
|
|
return
|
|
end
|
|
|
|
if event.element.name == "player_auth_dialog_close_button" then
|
|
local parent = assert(event.element.parent)
|
|
assert(parent.parent).destroy()
|
|
|
|
elseif event.element.name == "player_auth_verify_code_button" then
|
|
local parent = assert(event.element.parent)
|
|
local verify_code = assert(parent.player_auth_verify_code_input).text
|
|
local player_name = game.players[event.player_index].name
|
|
clusterio_api.send_json("player_auth", {
|
|
type = "set_verify_code",
|
|
player = player_name,
|
|
verify_code = verify_code,
|
|
})
|
|
end
|
|
end
|
|
|
|
--- @param event EventData.on_gui_closed
|
|
auth.events[defines.events.on_gui_closed] = function(event)
|
|
if
|
|
event.element
|
|
and event.element.valid
|
|
and event.element.name == "player_auth_dialog"
|
|
then
|
|
event.element.destroy()
|
|
end
|
|
end
|
|
|
|
return auth
|