[MIRROR] Load alien/job whitelists from database, if enabled (#11751)

Co-authored-by: Selis <12716288+ItsSelis@users.noreply.github.com>
Co-authored-by: Kashargul <KashL@t-online.de>
This commit is contained in:
CHOMPStation2StaffMirrorBot
2025-11-05 02:46:01 -07:00
committed by GitHub
parent a8b89de4fd
commit 3139b7684f
10 changed files with 422 additions and 46 deletions

View File

@@ -295,7 +295,7 @@ LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY INVOKER
COMMENT 'Inserts a new row into \'chatlogs_rounds\' and deletes the oldest entry, if the ckey already has 10 round id\'s stored.'
COMMENT 'Inserts a new row into \'chatlogs_rounds\' and deletes the oldest entry, if the ckey already has 10 round ids stored.'
BEGIN
INSERT IGNORE INTO chatlogs_rounds(round_id, ckey) VALUES (p_round_id, p_ckey);
@@ -307,6 +307,16 @@ END IF;
END
DELIMITER ;
-- Table structure for table `whitelist`
CREATE TABLE `whitelist` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`ckey` VARCHAR(45) NOT NULL COLLATE 'utf8mb4_uca1400_ai_ci',
`kind` VARCHAR(255) NOT NULL COLLATE 'utf8mb4_uca1400_ai_ci',
`entry` VARCHAR(255) NOT NULL COLLATE 'utf8mb4_uca1400_ai_ci',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `ckey_kind_entry` (`ckey`, `kind`, `entry`) USING BTREE
) ENGINE=InnoDB COLLATE='utf8mb4_uca1400_ai_ci';
-- CHOMPedit Start
CREATE TABLE IF NOT EXISTS `erro_mentor` (
`id` int(11) NOT NULL AUTO_INCREMENT,

View File

@@ -526,11 +526,10 @@ Ignore_errors instructes mysql to continue inserting rows if some of them have e
Close()
status = DB_QUERY_STARTED
if(async)
/*if(!MC_RUNNING(SSdbcore.init_stage))
if(!MC_RUNNING(SSdbcore.init_stage))
SSdbcore.run_query_sync(src)
else
SSdbcore.queue_query(src)*/
SSdbcore.run_query_sync(src)
SSdbcore.queue_query(src)
sync()
else
var/job_result_str = rustg_sql_query_blocking(connection, sql, json_encode(arguments))

View File

@@ -1,11 +1,68 @@
#define WHITELISTFILE "data/whitelist.txt"
GLOBAL_LIST_EMPTY(whitelist)
GLOBAL_LIST_EMPTY(job_whitelist)
GLOBAL_LIST_EMPTY(alien_whitelist)
/hook/startup/proc/loadWhitelist()
if(CONFIG_GET(flag/usewhitelist))
load_whitelist()
return 1
// Not yet implemented
//ADMIN_VERB(open_whitelist_editor, R_ADMIN, "Open Whitelist Editor", "Opens the editor for alien- and jobwhitelists.", ADMIN_CATEGORY_GAME)
// if(user.holder)
// user.holder.whitelist_editor = new /datum/whitelist_editor()
// user.holder.whitelist_editor.tgui_interact(user.mob)
/datum/whitelist_editor
/datum/whitelist_editor/tgui_state(mob/user)
return ADMIN_STATE(R_ADMIN)
/datum/whitelist_editor/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "WhitelistEdit")
ui.open()
/datum/whitelist_editor/tgui_data(mob/user)
var/list/data = list()
data["alienwhitelist"] = GLOB.alien_whitelist
data["jobwhitelist"] = GLOB.job_whitelist
return data
/datum/whitelist_editor/tgui_static_data(mob/user)
var/list/data = list()
data["species_requiring_whitelist"] = GLOB.whitelisted_species
return data
/datum/whitelist_editor/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
switch(action)
if("add_alienwhitelist")
if (!CONFIG_GET(flag/sql_enabled))
to_chat(ui.user, "This action is not supported while the database is disabled. Please edit [global.config.directory]/alienwhitelist.txt.")
return
// TODO: Add to database
. = TRUE
if("remove_alienwhitelist")
if (!CONFIG_GET(flag/sql_enabled))
to_chat(ui.user, "This action is not supported while the database is disabled. Please edit [global.config.directory]/alienwhitelist.txt.")
return
// TODO: Remove from database
. = TRUE
if("reload_alienwhitelist")
reload_alienwhitelist()
. = TRUE
if("reload_jobwhitelist")
reload_jobwhitelist()
. = TRUE
/proc/load_whitelist()
GLOB.whitelist = world.file2list(WHITELISTFILE)
@@ -20,33 +77,58 @@ GLOBAL_LIST_EMPTY(whitelist)
return 0
return ("[M.ckey]" in GLOB.whitelist)
GLOBAL_LIST_EMPTY(alien_whitelist)
/proc/load_alienwhitelist(dbfail = FALSE)
if (CONFIG_GET(flag/sql_enabled) && !dbfail)
var/datum/db_query/query_load_alienwhistelist = SSdbcore.NewQuery("SELECT ckey, entry FROM [format_table_name("whitelist")] WHERE kind = 'species'")
if(!query_load_alienwhistelist.Execute())
message_admins("Error loading alienwhitelist from database. Loading from [global.config.directory]/alienwhitelist.txt.")
log_sql("Error loading alienwhitelist from database. Loading from [global.config.directory]/alienwhitelist.txt.")
load_alienwhitelist(dbfail = TRUE)
return
else
while(query_load_alienwhistelist.NextRow())
var/ckey = query_load_alienwhistelist.item[1]
var/entry = query_load_alienwhistelist.item[2]
/hook/startup/proc/loadAlienWhitelist()
if(CONFIG_GET(flag/usealienwhitelist))
load_alienwhitelist()
return 1
/proc/load_alienwhitelist()
var/text = file2text("config/alienwhitelist.txt")
if (!text)
log_world("Failed to load config/alienwhitelist.txt")
var/list/our_whitelists = GLOB.alien_whitelist[ckey]
if(!our_whitelists) // Guess this is their first/only whitelist entry
our_whitelists = list()
GLOB.alien_whitelist[ckey] = our_whitelists
our_whitelists += entry
qdel(query_load_alienwhistelist)
else
var/lines = splittext(text, "\n") // Now we've got a bunch of "ckey = something" strings in a list
for(var/line in lines)
var/list/left_and_right = splittext(line, " - ") // Split it on the dash into left and right
if(LAZYLEN(left_and_right) != 2)
WARNING("Alien whitelist entry is invalid: [line]") // If we didn't end up with a left and right, the line is bad
continue
var/key = left_and_right[1]
if(key != ckey(key))
WARNING("Alien whitelist entry appears to have key, not ckey: [line]") // The key contains invalid ckey characters
continue
var/list/our_whitelists = GLOB.alien_whitelist[key] // Try to see if we have one already and add to it
if(!our_whitelists) // Guess this is their first/only whitelist entry
our_whitelists = list()
GLOB.alien_whitelist[key] = our_whitelists
our_whitelists += left_and_right[2]
var/text = file2text("[global.config.directory]/alienwhitelist.txt")
if (!text)
log_world("Failed to load [global.config.directory]/alienwhitelist.txt")
else
var/lines = splittext(text, "\n") // Now we've got a bunch of "ckey = something" strings in a list
for(var/line in lines)
var/list/left_and_right = splittext(line, " - ") // Split it on the dash into left and right
if(LAZYLEN(left_and_right) != 2)
WARNING("Alien whitelist entry is invalid: [line]") // If we didn't end up with a left and right, the line is bad
continue
var/key = left_and_right[1]
if(key != ckey(key))
WARNING("Alien whitelist entry appears to have key, not ckey: [line]") // The key contains invalid ckey characters
continue
var/list/our_whitelists = GLOB.alien_whitelist[key] // Try to see if we have one already and add to it
if(!our_whitelists) // Guess this is their first/only whitelist entry
our_whitelists = list()
GLOB.alien_whitelist[key] = our_whitelists
our_whitelists += left_and_right[2]
#ifdef TESTING
var/msg = "Alienwhitelist Built:\n"
for(var/key in GLOB.alien_whitelist)
msg += "\t[key]:\n"
for(var/value in GLOB.alien_whitelist[key])
msg += "\t\t- [value]\n"
testing(msg)
#endif
/proc/reload_alienwhitelist()
GLOB.alien_whitelist.Cut()
load_alienwhitelist()
/proc/is_alien_whitelisted(client/C, var/datum/species/species)
//They are admin or the whitelist isn't in use
@@ -71,6 +153,78 @@ GLOBAL_LIST_EMPTY(alien_whitelist)
// Go apply!
return FALSE
/proc/load_jobwhitelist(dbfail = FALSE)
if (CONFIG_GET(flag/sql_enabled) && !dbfail)
var/datum/db_query/query_load_jobwhitelist = SSdbcore.NewQuery("SELECT ckey, entry FROM [format_table_name("whitelist")] WHERE kind = 'job'")
if(!query_load_jobwhitelist.Execute())
message_admins("Error loading jobwhitelist from database. Loading from [global.config.directory]/jobwhitelist.txt.")
log_sql("Error loading jobwhitelist from database. Loading from [global.config.directory]/jobwhitelist.txt.")
load_jobwhitelist(dbfail = TRUE)
return
else
while(query_load_jobwhitelist.NextRow())
var/ckey = query_load_jobwhitelist.item[1]
var/entry = query_load_jobwhitelist.item[2]
var/list/our_whitelists = GLOB.job_whitelist[ckey]
if(!our_whitelists) // Guess this is their first/only whitelist entry
our_whitelists = list()
GLOB.job_whitelist[ckey] = our_whitelists
our_whitelists += entry
qdel(query_load_jobwhitelist)
else
var/text = file2text("[global.config.directory]/jobwhitelist.txt")
if (!text)
log_world("Failed to load [global.config.directory]/jobwhitelist.txt")
else
var/lines = splittext(text, "\n") // Now we've got a bunch of "ckey = something" strings in a list
for(var/line in lines)
var/list/left_and_right = splittext(line, " - ") // Split it on the dash into left and right
if(LAZYLEN(left_and_right) != 2)
warning("Alien whitelist entry is invalid: [line]") // If we didn't end up with a left and right, the line is bad
continue
var/key = left_and_right[1]
if(key != ckey(key))
warning("Alien whitelist entry appears to have key, not ckey: [line]") // The key contains invalid ckey characters
continue
var/list/our_whitelists = GLOB.job_whitelist[key] // Try to see if we have one already and add to it
if(!our_whitelists) // Guess this is their first/only whitelist entry
our_whitelists = list()
GLOB.job_whitelist[key] = our_whitelists
our_whitelists += left_and_right[2]
/proc/reload_jobwhitelist()
GLOB.job_whitelist.Cut()
load_jobwhitelist()
/proc/is_job_whitelisted(mob/M, var/rank)
// Check if the job actually requires a whitelist
var/datum/job/job = job_master.GetJob(rank)
if(!job.whitelist_only)
return TRUE
// Visitor not Assistant
if(rank == JOB_ALT_VISITOR)
return TRUE
// Let R_ADMIN permission bypass the whitelist
if(check_rights(R_ADMIN, 0))
return TRUE
// Whitelist empty
if(!GLOB.job_whitelist)
return FALSE
//Search the whitelist
if(M && M.client && rank)
var/list/our_whitelists = GLOB.job_whitelist[M.client.ckey]
if("All" in our_whitelists)
return TRUE
if(lowertext(rank) in our_whitelists)
return TRUE
return FALSE
/proc/is_lang_whitelisted(mob/M, var/datum/language/language)
//They are admin or the whitelist isn't in use
if(whitelist_overrides(M))

View File

@@ -166,6 +166,15 @@ GLOBAL_VAR(restart_counter)
GLOB.timezoneOffset = world.timezone * 36000
callHook("startup")
// This should probably moved somewhere else
// Maybe even a comsig?
if(CONFIG_GET(flag/usewhitelist))
load_whitelist()
if(CONFIG_GET(flag/usealienwhitelist))
load_alienwhitelist()
load_jobwhitelist()
//Emergency Fix
load_mods()
//end-emergency fix

View File

@@ -88,7 +88,6 @@ var/list/admin_verbs_admin = list(
/client/proc/toggle_spawning_with_recolour,
/client/proc/start_vote,
/client/proc/hide_motion_tracker_feedback,
/client/proc/reload_jobwhitelist, //ChompADD
/client/proc/reload_alienwhitelist //ChompADD
)
@@ -224,7 +223,6 @@ var/list/admin_verbs_debug = list(
/client/proc/stop_sounds,
/client/proc/spawn_reagent,
/datum/admins/proc/quick_authentic_nif, //CHOMPStation add
/client/proc/reload_jobwhitelist, //ChompADD
/client/proc/reload_alienwhitelist, //ChompADD
/client/proc/reload_configuration //CHOMPAdd
)
@@ -317,7 +315,6 @@ var/list/admin_verbs_mod = list(
/datum/admins/proc/sendFax,
/datum/admins/proc/view_persistent_data,
/client/proc/start_vote,
/client/proc/reload_jobwhitelist, //ChompADD
/client/proc/reload_alienwhitelist //ChompADD
)
@@ -451,6 +448,5 @@ var/list/admin_verbs_event_manager = list(
/client/proc/modify_event_collector,
/client/proc/induce_malfunction,
/datum/admins/proc/quick_authentic_nif, //CHOMPStation add
/client/proc/reload_jobwhitelist, //ChompADD
/client/proc/reload_alienwhitelist //ChompADD
)

View File

@@ -31,6 +31,7 @@ GLOBAL_PROTECT(href_token)
var/datum/filter_editor/filteriffic
var/datum/particle_editor/particle_test
var/datum/whitelist_editor/whitelist_editor
/// A lazylist of tagged datums, for quick reference with the View Tags verb
var/list/tagged_datums

View File

@@ -159,14 +159,8 @@
else
icon = 'icons/obj/pda_old.dmi'
log_runtime("Invalid switch for PDA, defaulting to old PDA icons. [pdachoice] chosen.")
//add_overlay("pda-pen") //ChompEDIT no icon ops on New
start_program(find_program(/datum/data/pda/app/main_menu))
//ChompEDIT START - move icon ops to initialize
/obj/item/pda/Initialize(mapload)
. = ..()
add_overlay("pda-pen")
//ChompEDIT END
start_program(find_program(/datum/data/pda/app/main_menu))
/obj/item/pda/proc/can_use(mob/user)
return (tgui_status(user, GLOB.tgui_inventory_state) == STATUS_INTERACTIVE)

View File

@@ -30,7 +30,7 @@
admin_only = FALSE
/datum/tgs_chat_command/parsetest/Run(datum/tgs_chat_user/sender, params)
return "```You passed:[params]```"
return new /datum/tgs_message_content("```You passed:[params]```")
/datum/tgs_chat_command/staffwho
name = "staffwho"
@@ -378,3 +378,168 @@ GLOBAL_LIST_EMPTY(pending_discord_registrations)
if("dust")
real_target.dust()
return "Smite [smite_name] sent!"
#define VALID_ACTIONS list("add", "remove", "list")
#define VALID_KINDS list("job", "species")
#define VALID_USAGE "whitelist \[[list2text(VALID_ACTIONS, ", ")]\] \[[list2text(VALID_KINDS, ", ")]\] <ckey> (role)"
/datum/tgs_chat_command/whitelist
name = "whitelist"
help_text = "allows the management of player whitelists. Usage: whitelist \[add, remove, list\] \[job, species\] <ckey> (role)"
admin_only = TRUE
/datum/tgs_chat_command/whitelist/Run(datum/tgs_chat_user/sender, params)
var/list/message_as_list = splittext(params, " ")
var/datum/tgs_message_content/message = new("Invalid return message.")
// Check if the command is valid
if(!CONFIG_GET(flag/sql_enabled))
message.text = "```A database is required to be set up for this feature.```"
return message
if(!LAZYLEN(message_as_list))
message.text = "```Invalid command usage: [VALID_USAGE]```"
return message
var/action = message_as_list[1]
if(!(action in VALID_ACTIONS))
message.text = "```First param must be a valid action.```"
return message
message_as_list.Cut(1, 2)
if(!LAZYLEN(message_as_list))
message.text = "```Invalid command usage: [VALID_USAGE]```"
return message
var/kind = message_as_list[1]
if(!(kind in VALID_KINDS))
message.text = "```Second param must be a valid whitelist kind.```"
return message
message_as_list.Cut(1, 2)
if(!LAZYLEN(message_as_list))
message.text = "```Invalid command usage: [VALID_USAGE]```"
return message
var/ckey = message_as_list[1]
if(!istext(ckey))
message.text = "```Third param must be a valid ckey.```"
return message
// Role is not required for listing the roles of a ckey
var/role
if(action != "list")
message_as_list.Cut(1, 2)
if(!LAZYLEN(message_as_list))
message.text = "```Invalid command usage: [VALID_USAGE]```"
return message
role = message_as_list[1]
if(!istext(role))
message.text = "```Fourth param must be a valid whitelist role.```"
return message
// Resolve the action
switch(action)
if("add")
var/datum/db_query/command_add = SSdbcore.NewQuery(
"INSERT INTO [format_table_name("whitelist")] (ckey, kind, entry) VALUES (:ckey, :kind, :entry)",
list("ckey" = ckey, "kind" = kind, "entry" = role)
)
if(!command_add.Execute())
log_sql("Error while trying to add [ckey] to the [role] [kind] whitelist.")
message.text = "Error while trying to add [ckey] to the [role] [kind] whitelist. Please review SQL logs."
return message
qdel(command_add)
var/list/our_whitelists
if(kind == "job")
our_whitelists = GLOB.job_whitelist[ckey]
if(!our_whitelists)
our_whitelists = list()
GLOB.job_whitelist[ckey] = our_whitelists
if(kind == "species")
our_whitelists = GLOB.alien_whitelist[ckey]
if(!our_whitelists)
our_whitelists = list()
GLOB.alien_whitelist[ckey] = our_whitelists
if(our_whitelists)
our_whitelists |= role
if("remove")
var/datum/db_query/command_remove = SSdbcore.NewQuery(
"DELETE FROM [format_table_name("whitelist")] WHERE ckey = :ckey AND kind = :kind AND entry = :entry",
list("ckey" = ckey, "kind" = kind, "entry" = role)
)
if(!command_remove.Execute())
log_sql("Error while trying to remove [ckey] from the [role] [kind] whitelist.")
message.text = "Error while trying to remove [ckey] from the [role] [kind] whitelist. Please review SQL logs."
return message
qdel(command_remove)
var/list/our_whitelists
if(kind == "job")
our_whitelists = GLOB.job_whitelist[ckey]
if(!our_whitelists)
our_whitelists = list()
GLOB.job_whitelist[ckey] = our_whitelists
if(kind == "species")
our_whitelists = GLOB.alien_whitelist[ckey]
if(!our_whitelists)
our_whitelists = list()
GLOB.alien_whitelist[ckey] = our_whitelists
if(our_whitelists && (role in our_whitelists))
our_whitelists -= role
// Listing all whitelists for a specific ckey
if("list")
var/datum/tgs_chat_embed/structure/embed = new()
var/found = FALSE
message.text = ""
message.embed = embed
embed.title = "Whitelists for [ckey]"
var/datum/db_query/query_list = SSdbcore.NewQuery(
"SELECT kind, entry FROM [format_table_name("whitelist")] WHERE ckey = :ckey",
list("ckey" = ckey)
)
if(!query_list.Execute())
log_sql("Error while trying to query whitelists for [ckey].")
embed.description = "Error while trying to query whitelists for [ckey]. Please review SQL logs."
embed.colour = "#FF0000"
return message
else
while(query_list.NextRow())
var/kind_query_result = query_list.item[1]
var/entry_query_result = query_list.item[2]
embed.description += "- [kind_query_result] - [entry_query_result]\n"
found = TRUE
qdel(query_list)
if(!found)
embed.description += "No whitelist entries found for [ckey]"
return message
// Notify the player of the change
var/key_to_find = "[ckey(ckey)]"
if(length(key_to_find))
var/client/user
for(var/client/C in GLOB.clients)
if(C.ckey == key_to_find)
user = C
break
to_chat(user, span_info("You have been [action][action == "remove" ? "d" : "ed"] to the [kind] whitelist of [role] by an administrator."))
// Notify the admins on discord that it was successful
message.text = "\[Whitelist Edit\] [ckey] has been [action][action == "remove" ? "d" : "ed"] to [kind] whitelist: [role]"
log_admin(message.text)
message_admins(message.text)
return message
#undef VALID_USAGE
#undef VALID_KINDS
#undef VALID_ACTIONS

View File

@@ -0,0 +1,49 @@
input_file = 'config/alienwhitelist.txt'
output_file = 'whitelist.sql'
table_name = 'whitelist'
with open(input_file, 'r', encoding='utf-8') as infile, \
open(output_file, 'w', encoding='utf-8') as outfile:
for line in infile:
line = line.strip()
if not line:
continue
if "#" in line:
print(f"Skipping commented line: {line}")
continue
# Split on ' - ', expecting exactly two parts
parts = line.split(' - ')
if len(parts) != 2:
print(f"Skipping invalid line: {line}")
continue
username, entry = (p.replace("'", "''") for p in parts) # Escape single quotes
kind = "species"
sql = (
f"INSERT INTO {table_name} (ckey, entry, kind) "
f"VALUES ('{username}', '{entry}', '{kind}');\n"
)
outfile.write(sql)
input_file = 'config/jobwhitelist.txt'
with open(input_file, 'r', encoding='utf-8') as infile, \
open(output_file, 'a', encoding='utf-8') as outfile:
for line in infile:
line = line.strip()
if not line:
continue
if "#" in line:
print(f"Skipping commented line: {line}")
continue
# Split on ' - ', expecting exactly two parts
parts = line.split(' - ')
if len(parts) != 2:
print(f"Skipping invalid line: {line}")
continue
username, entry = (p.replace("'", "''") for p in parts) # Escape single quotes
kind = "job"
sql = (
f"INSERT INTO {table_name} (ckey, entry, kind) "
f"VALUES ('{username}', '{entry}', '{kind}');\n"
)
outfile.write(sql)

View File

@@ -1138,7 +1138,6 @@
#include "code\game\jobs\job_controller.dm"
#include "code\game\jobs\jobs.dm"
#include "code\game\jobs\whitelist.dm"
#include "code\game\jobs\whitelist_vr.dm"
#include "code\game\jobs\job\_alt_title.dm"
#include "code\game\jobs\job\assistant.dm"
#include "code\game\jobs\job\captain.dm"