mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-09-04 08:13:23 +00:00
feat: add LB migration and reorganize configuration
This commit is contained in:
@@ -903,7 +903,7 @@ local function cleanup_retained_data()
|
||||
},
|
||||
})
|
||||
if not success then
|
||||
print("[sky_phone] Companies retention cleanup failed.")
|
||||
Bridge.Debug("error", "[sky_phone] Companies retention cleanup failed.")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@ local function get_calling_resource(export_name)
|
||||
return owner_resource
|
||||
end
|
||||
|
||||
print(("[%s] %s rejected: the export must be called by another resource."):format(
|
||||
Bridge.Debug("warn", "[%s] %s rejected: the export must be called by another resource.",
|
||||
RESOURCE_NAME,
|
||||
export_name
|
||||
))
|
||||
)
|
||||
return nil, "invalid_owner"
|
||||
end
|
||||
|
||||
@@ -31,11 +31,11 @@ local function add_high_application(app_name, data, locales)
|
||||
locales
|
||||
)
|
||||
if not definition then
|
||||
print(("[%s] High Phone registration rejected for %s: %s."):format(
|
||||
Bridge.Debug("warn", "[%s] High Phone registration rejected for %s: %s.",
|
||||
RESOURCE_NAME,
|
||||
owner_resource,
|
||||
definition_error
|
||||
))
|
||||
)
|
||||
return false, definition_error
|
||||
end
|
||||
|
||||
@@ -77,9 +77,9 @@ end
|
||||
RegisterNetEvent("sky_phone:compat:high:server:requestSnapshot", function()
|
||||
local player_source = source
|
||||
if player_source <= 0 then
|
||||
print(("[%s] Rejected High Phone snapshot request without a player source."):format(
|
||||
Bridge.Debug("warn", "[%s] Rejected High Phone snapshot request without a player source.",
|
||||
RESOURCE_NAME
|
||||
))
|
||||
)
|
||||
return
|
||||
end
|
||||
|
||||
@@ -91,10 +91,10 @@ RegisterNetEvent("sky_phone:compat:high:server:requestSnapshot", function()
|
||||
local log_elapsed = last_log and now - last_log or SNAPSHOT_REJECTION_LOG_COOLDOWN_MS
|
||||
if log_elapsed < 0 or log_elapsed >= SNAPSHOT_REJECTION_LOG_COOLDOWN_MS then
|
||||
snapshot_rejection_logs[player_source] = now
|
||||
print(("[%s] Rate-limited High Phone snapshot request from player %s."):format(
|
||||
Bridge.Debug("warn", "[%s] Rate-limited High Phone snapshot request from player %s.",
|
||||
RESOURCE_NAME,
|
||||
player_source
|
||||
))
|
||||
)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
@@ -53,9 +53,13 @@ local function register_policy(policy)
|
||||
local app_id = policy.id
|
||||
local existing = policies_by_id[app_id]
|
||||
if existing then
|
||||
print((
|
||||
"[sky_phone] Rejected duplicate custom app policy '%s' from '%s'; it is already owned by '%s'."
|
||||
):format(app_id, policy.ownerResource, existing.ownerResource))
|
||||
Bridge.Debug(
|
||||
"warn",
|
||||
"[sky_phone] Rejected duplicate custom app policy '%s' from '%s'; it is already owned by '%s'.",
|
||||
app_id,
|
||||
policy.ownerResource,
|
||||
existing.ownerResource
|
||||
)
|
||||
return false, "duplicate_app_id"
|
||||
end
|
||||
|
||||
|
||||
@@ -233,6 +233,71 @@ local schema = {
|
||||
},
|
||||
tableOptions = "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
|
||||
},
|
||||
{
|
||||
name = "sky_phone_migrations",
|
||||
columns = {
|
||||
{ name = "name", type = "VARCHAR(96) NOT NULL", characterSet = "ascii", collation = "ascii_bin" },
|
||||
{ name = "source", type = "VARCHAR(32) NOT NULL", characterSet = "ascii", collation = "ascii_bin" },
|
||||
{ name = "stats", type = "LONGTEXT NULL" },
|
||||
{ name = "completed_at", type = "DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP" },
|
||||
},
|
||||
primaryKey = "name",
|
||||
indexes = {
|
||||
{ name = "idx_sky_phone_migrations_source", columns = "(`source`, `completed_at`)" },
|
||||
},
|
||||
tableOptions = "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
|
||||
},
|
||||
{
|
||||
name = "sky_phone_migration_numbers",
|
||||
columns = {
|
||||
{ name = "source", type = "VARCHAR(32) NOT NULL", characterSet = "ascii", collation = "ascii_bin" },
|
||||
{ name = "source_number", type = "VARCHAR(64) NOT NULL" },
|
||||
{ name = "phone_number", type = "VARCHAR(24) NOT NULL", characterSet = "ascii", collation = "ascii_bin" },
|
||||
{ name = "sim_id", type = "CHAR(36) NOT NULL", characterSet = "ascii", collation = "ascii_bin" },
|
||||
{ name = "owned", type = "TINYINT(1) NOT NULL DEFAULT 0" },
|
||||
{ name = "created_at", type = "DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP" },
|
||||
},
|
||||
primaryKey = { "source", "source_number" },
|
||||
uniqueKeys = {
|
||||
{ name = "uniq_sky_phone_migration_number", columns = "(`source`, `phone_number`)" },
|
||||
},
|
||||
indexes = {
|
||||
{ name = "idx_sky_phone_migration_numbers_sim", columns = "(`sim_id`)" },
|
||||
},
|
||||
foreignKeys = {
|
||||
{ column = "sim_id", references = "`sky_phone_sims` (`id`) ON DELETE CASCADE" },
|
||||
},
|
||||
tableOptions = "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
|
||||
},
|
||||
{
|
||||
name = "sky_phone_migration_owners",
|
||||
columns = {
|
||||
{ name = "source", type = "VARCHAR(32) NOT NULL", characterSet = "ascii", collation = "ascii_bin" },
|
||||
{ name = "source_phone_id", type = "VARCHAR(100) NOT NULL" },
|
||||
{ name = "source_owner_id", type = "VARCHAR(100) NOT NULL" },
|
||||
{ name = "owner_identifier", type = "VARCHAR(80) NOT NULL", characterSet = "ascii", collation = "ascii_bin" },
|
||||
{ name = "source_phone_number", type = "VARCHAR(64) NOT NULL" },
|
||||
{ name = "device_imei", type = "CHAR(15) NOT NULL", characterSet = "ascii", collation = "ascii_bin" },
|
||||
{ name = "sim_id", type = "CHAR(36) NOT NULL", characterSet = "ascii", collation = "ascii_bin" },
|
||||
{ name = "account_id", type = "BIGINT UNSIGNED NULL" },
|
||||
{ name = "created_at", type = "DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP" },
|
||||
},
|
||||
primaryKey = { "source", "source_phone_id" },
|
||||
uniqueKeys = {
|
||||
{ name = "uniq_sky_phone_migration_owner_number", columns = "(`source`, `source_phone_number`)" },
|
||||
},
|
||||
indexes = {
|
||||
{ name = "idx_sky_phone_migration_owner", columns = "(`source`, `owner_identifier`)" },
|
||||
{ name = "idx_sky_phone_migration_owner_device", columns = "(`device_imei`)" },
|
||||
{ name = "idx_sky_phone_migration_owner_account", columns = "(`account_id`)" },
|
||||
},
|
||||
foreignKeys = {
|
||||
{ column = "device_imei", references = "`sky_phone_devices` (`imei`) ON DELETE CASCADE" },
|
||||
{ column = "sim_id", references = "`sky_phone_sims` (`id`) ON DELETE CASCADE" },
|
||||
{ column = "account_id", references = "`sky_phone_accounts` (`id`) ON DELETE SET NULL" },
|
||||
},
|
||||
tableOptions = "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
|
||||
},
|
||||
{
|
||||
name = "sky_phone_device_data",
|
||||
columns = {
|
||||
|
||||
@@ -14,14 +14,12 @@ local custom_music_extensions = {
|
||||
wav = true,
|
||||
webm = true,
|
||||
}
|
||||
local password_pepper = GetConvar(Config.FlipTok.PasswordPepperConvar, "")
|
||||
local password_pepper = tostring(Config.Server.FlipTokPasswordPepper or "")
|
||||
|
||||
if password_pepper == "" then
|
||||
Bridge.Debug(
|
||||
"warn",
|
||||
"[sky_phone] FlipTok password pepper convar '%s' is empty; configure it before production use.",
|
||||
Config.FlipTok.PasswordPepperConvar,
|
||||
{ always = true }
|
||||
"[sky_phone] Config.Server.FlipTokPasswordPepper is empty; configure it in config/config.lua before production use."
|
||||
)
|
||||
end
|
||||
|
||||
@@ -921,7 +919,7 @@ RegisterCommand(Config.FlipTok.VerifyCommand, function(source, arguments)
|
||||
end
|
||||
local function send_command_feedback(message, notification_type)
|
||||
if source == 0 then
|
||||
print(message)
|
||||
Bridge.Debug(notification_type == "error" and "error" or "info", message)
|
||||
return
|
||||
end
|
||||
|
||||
@@ -932,7 +930,11 @@ RegisterCommand(Config.FlipTok.VerifyCommand, function(source, arguments)
|
||||
end
|
||||
if source ~= 0 and not Bridge.Framework.HasAdminGroup(source, Config.FlipTok.AdminGroups) then
|
||||
send_command_feedback(command_locale.noPermission, "error")
|
||||
print(("[sky_phone] Player %d attempted to use the FlipTok verification command without an admin group."):format(source))
|
||||
Bridge.Debug(
|
||||
"warn",
|
||||
"[sky_phone] Player %d attempted to use the FlipTok verification command without an admin group.",
|
||||
source
|
||||
)
|
||||
return
|
||||
end
|
||||
local handle = type(arguments[1]) == "string" and arguments[1]:lower():gsub("^@", "") or ""
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -970,6 +970,9 @@ AddEventHandler("playerDropped", function()
|
||||
end)
|
||||
|
||||
if not api_configured() then
|
||||
print("^3[sky_phone] Camera uploads and FiveManage imports are disabled until Config.Media.FiveManage.ApiKey is set in config/media.lua.^7")
|
||||
Bridge.Debug(
|
||||
"warn",
|
||||
"[sky_phone] Camera uploads and FiveManage imports are disabled until Config.Media.FiveManage.ApiKey is set in config/config.lua."
|
||||
)
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -10,13 +10,11 @@ local auth_attempts = {}
|
||||
local operation_attempts = {}
|
||||
local character_device_cache = {}
|
||||
local max_device_data_bytes = 100000
|
||||
local passcode_pepper = GetConvar(Config.Security.PasscodePepperConvar, "")
|
||||
local passcode_pepper = tostring(Config.Server.PasscodePepper or "")
|
||||
if passcode_pepper == "" then
|
||||
Bridge.Debug(
|
||||
"warn",
|
||||
"[sky_phone] Passcode pepper convar '%s' is empty; configure it before production use.",
|
||||
Config.Security.PasscodePepperConvar,
|
||||
{ always = true }
|
||||
"[sky_phone] Config.Server.PasscodePepper is empty; configure it in config/config.lua before production use."
|
||||
)
|
||||
end
|
||||
local allowed_device_namespaces = {
|
||||
@@ -86,6 +84,36 @@ local function character_identifier(source)
|
||||
return identifier
|
||||
end
|
||||
|
||||
local function migrated_device_for_character(source)
|
||||
local identifier = character_identifier(source)
|
||||
if not identifier then
|
||||
return nil
|
||||
end
|
||||
|
||||
local rows = Bridge.Database.Query([[
|
||||
SELECT mapping.`device_imei`
|
||||
FROM `sky_phone_migration_owners` mapping
|
||||
JOIN `sky_phone_character_devices` character_device
|
||||
ON character_device.`owner_identifier` = mapping.`owner_identifier`
|
||||
AND character_device.`device_imei` = mapping.`device_imei`
|
||||
JOIN `sky_phone_devices` device ON device.`imei` = mapping.`device_imei`
|
||||
WHERE mapping.`source` = 'lb-phone' AND mapping.`owner_identifier` = ?
|
||||
ORDER BY mapping.`created_at` DESC
|
||||
LIMIT 1
|
||||
]], { identifier })
|
||||
local imei = rows[1] and rows[1].device_imei or nil
|
||||
if imei and not SkyPhoneImei.IsValid(imei) then
|
||||
Bridge.Debug(
|
||||
"error",
|
||||
"[sky_phone] LB Phone migration mapping contains invalid IMEI '%s' for '%s'.",
|
||||
tostring(imei),
|
||||
identifier
|
||||
)
|
||||
return nil
|
||||
end
|
||||
return imei
|
||||
end
|
||||
|
||||
local function load_character_device(source, identifier)
|
||||
identifier = identifier or character_identifier(source)
|
||||
if not identifier then
|
||||
@@ -304,6 +332,30 @@ local function ensure_device(source, slot)
|
||||
end
|
||||
|
||||
if not imei then
|
||||
imei = migrated_device_for_character(source)
|
||||
if imei then
|
||||
metadata.imei = imei
|
||||
local metadata_written = Bridge.Inventory.SetSlotMetadata(source, slot.slot, metadata)
|
||||
if not metadata_written then
|
||||
Bridge.Debug(
|
||||
"error",
|
||||
"[sky_phone] Inventory '%s' could not adopt migrated phone metadata for source %s slot %s.",
|
||||
Bridge.Inventory.GetResourceName(),
|
||||
tostring(source),
|
||||
tostring(slot.slot)
|
||||
)
|
||||
return nil, "metadata_unsupported"
|
||||
end
|
||||
Bridge.Debug(
|
||||
"info",
|
||||
"[sky_phone] Adopted LB Phone migrated device %s for source %s.",
|
||||
imei,
|
||||
tostring(source),
|
||||
{ always = true }
|
||||
)
|
||||
return imei
|
||||
end
|
||||
|
||||
imei = reserve_imei()
|
||||
metadata.imei = imei
|
||||
Bridge.Debug(
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
Bridge.Database.AfterMigration("sky_phone", function()
|
||||
local report_reasons = {}
|
||||
local password_pepper = GetConvar(Config.Picstagram.PasswordPepperConvar, "")
|
||||
local password_pepper = tostring(Config.Server.PicstagramPasswordPepper or "")
|
||||
|
||||
if password_pepper == "" then
|
||||
Bridge.Debug(
|
||||
"warn",
|
||||
"[sky_phone] Picstagram password pepper convar '%s' is empty; configure it before production use.",
|
||||
Config.Picstagram.PasswordPepperConvar,
|
||||
{ always = true }
|
||||
"[sky_phone] Config.Server.PicstagramPasswordPepper is empty; configure it in config/config.lua before production use."
|
||||
)
|
||||
end
|
||||
|
||||
@@ -1444,7 +1442,7 @@ RegisterCommand(Config.Picstagram.VerifyCommand, function(source, args)
|
||||
end
|
||||
local function send_command_feedback(message, notification_type)
|
||||
if source == 0 then
|
||||
print(message)
|
||||
Bridge.Debug(notification_type == "error" and "error" or "info", message)
|
||||
return
|
||||
end
|
||||
TriggerClientEvent("sky_phone:picstagram:command-feedback", source, {
|
||||
|
||||
Reference in New Issue
Block a user