refactors whitelist to toml config (#7182)

Co-authored-by: Zandario <zandarioh@gmail.com>
This commit is contained in:
silicons
2025-05-31 08:32:21 -09:00
committed by GitHub
parent 7e8cd3f5ac
commit 93501b2071
22 changed files with 172 additions and 172 deletions

View File

@@ -543,7 +543,6 @@
#include "code\controllers\verbs.dm"
#include "code\controllers\configuration\config_entry.dm"
#include "code\controllers\configuration\configuration.dm"
#include "code\controllers\configuration\whitelists.dm"
#include "code\controllers\configuration\entries\admin.dm"
#include "code\controllers\configuration\entries\chat_bridge.dm"
#include "code\controllers\configuration\entries\cross_server.dm"

View File

@@ -31,7 +31,7 @@ GLOBAL_REAL(RS##what, /datum/controller/repository/##what); \
RS##what.Initialize(); \
} \
/datum/controller/subsystem/repository/__get_all_repositories() { \
. = ..(); \
. = ..() || list(); \
. += RS##what; \
} \
/datum/controller/repository/##what

View File

@@ -40,7 +40,7 @@
#define SPECIES_ID_SCORI "scori"
#define SPECIES_ID_SERGLING "sergling"
#define SPECIES_ID_SHADEKIN "shadekin"
#define SPECIES_ID_SHADEKIN_BLACK "blackeyedshadekin"
#define SPECIES_ID_SHADEKIN_BLACK "shadekin_blackeyed"
#define SPECIES_ID_SHADOW "shadow"
#define SPECIES_ID_SKELETON "skeleton"
#define SPECIES_ID_SKRELL "skrell"

View File

@@ -75,12 +75,14 @@ DEFINE_BITFIELD(species_fluff_flags, list(
/// Species is selectable and visible in chargen. This must be on a species to be roundstart/latejoin.
#define SPECIES_SPAWN_CHARACTER (1<<1)
/// Must be whitelisted to play roundstart/latejoin.
/// TODO: get rid of this, rework whitelist system to config
#define SPECIES_SPAWN_WHITELISTED (1<<2)
/// Must be whitelisted to see this species at all.
#define SPECIES_SPAWN_SECRET (1<<3)
/// Cannot normally spawn; something must pass in PREFS_COPY_TO_NO_CHECK_SPECIES to spawn checks to use!
#define SPECIES_SPAWN_RESTRICTED (1<<4)
/// if set, check species.id in WL, otherwise use uid
/// TODO: get rid of this, rework whitelist system to config
#define SPECIES_SPAWN_WHITELIST_FLEXIBLE (1<<5)
//? FLAGS ABOVE ARE RELEVANT TO UI.
//? If you change them, change necessary TGUI too.

View File

@@ -12,6 +12,8 @@
* if a key isn't a list, it'll be turned into a list when two keys exist
*
* originally made for dynamic tool functions
*
* TODO: better name
*/
/proc/merge_double_lazy_assoc_list(list/A, list/B)
. = A.Copy()
@@ -25,3 +27,23 @@
.[key] = list(.[key], B[key])
else
.[key] = B[key]
/**
* merges two 2-deep lists, ergo list(key = list(values))
* dedupes values
*
* ## Input
*
* list("A" = list("a", "b", "c"))
* list("A" = list("d"))
*
* ## Output
*
* list("A" = list("a", "b", "c", "d"))
*/
/proc/merge_2_nested_list(list/A, list/B)
. = list()
for(var/k1 in A)
.[k1] = A[k1].Copy()
for(var/k2 in B)
.[k2] += B[k2]

View File

@@ -39,8 +39,6 @@
for(var/J in legacy_configs)
LoadEntries(J)
break
// loadmaplist(CONFIG_MAPS_FILE)
LoadWhitelists()
LoadMOTD()
loaded = TRUE

View File

@@ -1,97 +0,0 @@
// todo: rework whitelists, fuck.
/datum/controller/configuration
/// alien whitelist: list() of species **NAME** (not uid because headmins don't read code) = list(ckeys)
/// language whitelists also go in here because what the fuck i hate this.
var/list/cached_alien_whitelist = list()
/// job whitelist: list() of job **TITLE** (not uid because headmins don't read code) = list(ckeys)
var/list/cached_job_whitelist = list()
/**
* name and ckey must be CKEY()'d.
*/
/datum/controller/configuration/proc/check_alien_whitelist(name, ckey)
if(!config_legacy.usealienwhitelist)
// ignore
return TRUE
if(admin_datums[ckey])
// bypass
return TRUE
var/list/relevant = cached_alien_whitelist[name]
return relevant?.Find(ckey)
/**
* get every alien (species | language) someone's whitelisted for
* returns *names*, not uids.
*/
/datum/controller/configuration/proc/all_alien_whitelists_for(ckey)
. = list()
for(var/ayy in cached_alien_whitelist)
if(!(ckey in cached_alien_whitelist[ayy]))
continue
. += ayy
/**
* name, ckey must be CKEY()'d.
*/
/datum/controller/configuration/proc/check_job_whitelist(name, ckey)
if(admin_datums[ckey])
// bypass
return TRUE
var/list/relevant = cached_job_whitelist[name]
return relevant?.Find(ckey)
/datum/controller/configuration/proc/LoadWhitelists()
reload_alien_whitelist()
reload_job_whitelist()
/datum/controller/configuration/proc/reload_job_whitelist()
cached_job_whitelist = list()
var/fname = "config/jobwhitelist.txt"
if(!fexists(fname))
log_config("Failed to load [fname]")
return FALSE
var/list/lines = world.file2list(fname)
var/count = 0
for(var/line in lines)
++count
line = trim(line)
if(!length(line))
continue
var/list/parts = splittext(line, "-")
if(length(parts) != 2)
log_config("jobwhitelist - skipping line [count]: [line]")
continue
var/title = ckey(parts[2])
var/ckey = ckey(parts[1])
LAZYINITLIST(cached_job_whitelist[title])
if(ckey in cached_job_whitelist[title])
log_config("jobwhitelist - duplicate ckey [ckey] for [title]")
continue
LAZYADD(cached_job_whitelist[title], ckey)
return TRUE
/datum/controller/configuration/proc/reload_alien_whitelist()
cached_alien_whitelist = list()
var/fname = "config/alienwhitelist.txt"
if(!fexists(fname))
log_config("Failed to load [fname]")
return FALSE
var/list/lines = world.file2list(fname)
var/count = 0
for(var/line in lines)
++count
line = trim(line)
if(!length(line))
continue
var/list/parts = splittext(line, "-")
if(length(parts) != 2)
log_config("alienwhitelist - skipping line [count]: [line]")
continue
var/alien = ckey(parts[2])
var/ckey = ckey(parts[1])
LAZYINITLIST(cached_alien_whitelist[alien])
if(ckey in cached_alien_whitelist[alien])
log_config("alienwhitelist - duplicate ckey [ckey] for [alien]")
continue
LAZYADD(cached_alien_whitelist[alien], ckey)
return TRUE

View File

@@ -5,12 +5,23 @@
GLOBAL_REAL(Configuration, /datum/controller/toml_configuration)
// todo: /datum/controller/configuration
// todo: needs stronger vv guarding; it still exposes list refs.
/datum/controller/toml_configuration
/// Entries by type.
VAR_PRIVATE/list/datum/toml_config_entry/typed_entries
/// Entries as same structure as the underlying toml/json
VAR_PRIVATE/list/datum/toml_config_entry/keyed_entries
/// TODO: database whitelist when this is stupid
/// species id = list(ckeys)
VAR_PRIVATE/list/species_whitelist
/// TODO: database whitelist when this is stupid
/// language id = list(ckeys)
VAR_PRIVATE/list/language_whitelist
/// TODO: database whitelist when this is stupid
/// role id = list(ckeys)
VAR_PRIVATE/list/role_whitelist
/datum/controller/toml_configuration/CanProcCall(procname)
switch(procname)
if(NAMEOF_PROC(src, New), NAMEOF_PROC(src, Destroy), NAMEOF_PROC(src, Initialize))
@@ -19,7 +30,11 @@ GLOBAL_REAL(Configuration, /datum/controller/toml_configuration)
return FALSE
if(NAMEOF_PROC(src, get_sensitive_entry), NAMEOF_PROC(src, set_sensitive_entry))
return FALSE
if(NAMEOF_PROC(src, reload), NAMEOF_PROC(src, reset), NAMEOF_PROC(src, load), NAMEOF_PROC(src, recursively_load_from_list))
if(NAMEOF_PROC(src, reload))
return FALSE
if(NAMEOF_PROC(src, reset), NAMEOF_PROC(src, load), NAMEOF_PROC(src, load_impl))
return FALSE
if(NAMEOF_PROC(src, reset_whitelist), NAMEOF_PROC(src, load_whitelist), NAMEOF_PROC(src, load_whitelist_impl))
return FALSE
return ..()
@@ -120,6 +135,10 @@ GLOBAL_REAL(Configuration, /datum/controller/toml_configuration)
load("config.default/config.toml")
load("config/config.toml")
reset_whitelist()
load_whitelist("config.default/whitelist.toml")
load_whitelist("config/whitelist.toml")
/**
* Resets the configuration.
*/
@@ -150,9 +169,9 @@ GLOBAL_REAL(Configuration, /datum/controller/toml_configuration)
if(!decoded)
CRASH("failed to decode config [filelike]!")
recursively_load_from_list(decoded, keyed_entries)
load_impl(decoded, keyed_entries)
/datum/controller/toml_configuration/proc/recursively_load_from_list(list/decoded_list, list/entry_list)
/datum/controller/toml_configuration/proc/load_impl(list/decoded_list, list/entry_list)
if(!decoded_list || !entry_list)
return
for(var/key in decoded_list)
@@ -162,10 +181,83 @@ GLOBAL_REAL(Configuration, /datum/controller/toml_configuration)
if(!islist(next_entry_list))
// todo: warn
else
recursively_load_from_list(value, next_entry_list[key])
load_impl(value, next_entry_list[key])
else
var/datum/toml_config_entry/entry = entry_list[key]
if(!istype(entry))
// todo: warn
else
entry.apply(value)
/datum/controller/toml_configuration/proc/reset_whitelist()
role_whitelist = list()
species_whitelist = list()
language_whitelist = list()
/datum/controller/toml_configuration/proc/load_whitelist(filelike)
var/list/decoded
if(istext(filelike))
if(!fexists(filelike))
CRASH("failed to load [filelike]: does not exist")
decoded = rustg_read_toml_file(filelike)
else if(isfile(filelike))
// noa path, it might be rsc cache; rust_g can't read that directly.
fdel("tmp/config/loading.toml")
fcopy(filelike, "tmp/config/loading.toml")
decoded = rustg_read_toml_file("tmp/config/loading.toml")
fdel("tmp/config/loading.toml")
if(!decoded)
CRASH("failed to decode config [filelike]!")
load_whitelist_impl(decoded)
/datum/controller/toml_configuration/proc/load_whitelist_impl(list/decoded_list)
if(!decoded_list)
return
var/list/role_whitelist = sanitize_islist(deep_copy_list(decoded_list["whitelist"]?["role"]))
var/list/language_whitelist = sanitize_islist(deep_copy_list(decoded_list["whitelist"]?["language"]))
var/list/species_whitelist = sanitize_islist(deep_copy_list(decoded_list["whitelist"]?["species"]))
// fixup: make everything ckeys
for(var/list/root_list as anything in list(
role_whitelist,
language_whitelist,
species_whitelist,
))
for(var/i in 1 to length(root_list))
var/id = root_list[i]
var/list/ckey_list = root_list[id]
for(var/j in 1 to length(ckey_list))
ckey_list[j] = ckey(ckey_list[j])
src.role_whitelist = merge_2_nested_list(src.role_whitelist, role_whitelist)
src.language_whitelist = merge_2_nested_list(src.language_whitelist, language_whitelist)
src.species_whitelist = merge_2_nested_list(src.species_whitelist, species_whitelist)
/datum/controller/toml_configuration/proc/check_species_whitelist(id, ckey)
return ckey(ckey) in species_whitelist[id]
/datum/controller/toml_configuration/proc/check_role_whitelist(id, ckey)
return ckey(ckey) in role_whitelist[id]
/datum/controller/toml_configuration/proc/check_language_whitelist(id, ckey)
return ckey(ckey) in language_whitelist[id]
/datum/controller/toml_configuration/proc/get_all_species_whitelists_for_ckey(ckey)
. = list()
for(var/id in species_whitelist)
if(ckey in species_whitelist[id])
. += id
/datum/controller/toml_configuration/proc/get_all_role_whitelists_for_ckey(ckey)
. = list()
for(var/id in role_whitelist)
if(ckey in role_whitelist[id])
. += id
/datum/controller/toml_configuration/proc/get_all_language_whitelists_for_ckey(ckey)
. = list()
for(var/id in language_whitelist)
if(ckey in language_whitelist[id])
. += id

View File

@@ -121,7 +121,6 @@ GLOBAL_LIST(topic_status_cache)
#ifdef UNIT_TESTS
HandleTestRun()
#endif
if(config_legacy.ToRban)
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(ToRban_autoupdate)), 5 MINUTES)

View File

@@ -115,7 +115,7 @@
*/
/datum/role/job/proc/check_client_availability(client/C, check_char, latejoin)
. = NONE
if(whitelist_only && !config.check_job_whitelist(ckey(title), C.ckey))
if(whitelist_only && !Configuration.check_role_whitelist(id, C.ckey))
. |= ROLE_UNAVAILABLE_WHITELIST
if(!slots_remaining())
. |= ROLE_UNAVAILABLE_SLOTS_FULL
@@ -146,7 +146,7 @@
*/
/datum/role/job/proc/check_client_availability_one(client/C, check_char, latejoin)
. = NONE
if(whitelist_only && !config.check_job_whitelist(ckey(title), C.ckey))
if(whitelist_only && !Configuration.check_role_whitelist(id, C.ckey))
return ROLE_UNAVAILABLE_WHITELIST
else if(latejoin && !slots_remaining(TRUE))
return ROLE_UNAVAILABLE_SLOTS_FULL

View File

@@ -1,5 +1,5 @@
/mob/living/carbon/alien/diona/confirm_evolution()
if(!config.check_alien_whitelist(SPECIES_DIONA, ckey))
if(!Configuration.check_species_whitelist(SPECIES_ID_DIONA, ckey))
alert(src, "You are currently not whitelisted to play as a full diona.", "Evolution Error")
return

View File

@@ -194,7 +194,7 @@
continue
if(blacklist.len && (current_species_name in blacklist))
continue
if((S.species_spawn_flags & SPECIES_SPAWN_WHITELISTED) && !config.check_alien_whitelist(ckey(S.species_spawn_flags & SPECIES_SPAWN_WHITELIST_FLEXIBLE ? S.id : S.uid), ckey))
if((S.species_spawn_flags & SPECIES_SPAWN_WHITELISTED) && !Configuration.check_species_whitelist(S.species_spawn_flags & SPECIES_SPAWN_WHITELIST_FLEXIBLE ? S.id : S.uid, ckey))
continue
valid_species += current_species_name

View File

@@ -520,7 +520,7 @@ INITIALIZE_IMMEDIATE(/mob/new_player)
if(chosen_species && use_species_name)
// Have to recheck admin due to no usr at roundstart. Latejoins are fine though.
if(!(chosen_species.species_spawn_flags & SPECIES_SPAWN_WHITELISTED) || config.check_alien_whitelist(ckey(chosen_species.species_spawn_flags & SPECIES_SPAWN_WHITELIST_FLEXIBLE ? chosen_species.id : chosen_species.uid), ckey))
if(!(chosen_species.species_spawn_flags & SPECIES_SPAWN_WHITELISTED) || chosen_species.check_whitelist_for_ckey(ckey))
new_character = new(T, use_species_name)
if(!new_character)
@@ -610,7 +610,7 @@ INITIALIZE_IMMEDIATE(/mob/new_player)
if(!chosen_species)
return SPECIES_HUMAN
if(!(chosen_species.species_spawn_flags & SPECIES_SPAWN_WHITELISTED) || config.check_alien_whitelist(ckey(chosen_species.id), ckey))
if(!(chosen_species.species_spawn_flags & SPECIES_SPAWN_WHITELISTED) || chosen_species.check_whitelist_for_ckey(ckey))
return chosen_species.name
return SPECIES_HUMAN

View File

@@ -72,7 +72,7 @@
var/list/whitelisted_ids = CS.get_whitelisted_language_ids() // cache ids from character species for speed
for(var/id in extraneous)
var/datum/prototype/language/L = RSlanguages.fetch(id)
if((L.language_flags & LANGUAGE_WHITELISTED) && (!(L.id in whitelisted_ids)) && !config.check_alien_whitelist(ckey(L.name), prefs.client_ckey))
if((L.language_flags & LANGUAGE_WHITELISTED) && (!(L.id in whitelisted_ids)) && !Configuration.check_language_whitelist(L.id, prefs.client_ckey))
errors?.Add(SPAN_WARNING("[L] is a whitelisted language."))
return FALSE
return TRUE

View File

@@ -17,7 +17,7 @@
. += "<br>This is a [SPAN_RED("restricted")] species. You cannot join as this outside of special circumstances."
else if(CS.species_spawn_flags & SPECIES_SPAWN_WHITELISTED)
. += "<br>This is a whitelisted species. You "
if(config.check_alien_whitelist(ckey(CS.species_spawn_flags & SPECIES_SPAWN_WHITELIST_FLEXIBLE ? CS.superspecies_id : CS.uid), prefs.client_ckey))
if(CS.check_whitelist_for_ckey(prefs.client_ckey))
. += SPAN_GREEN("do")
else
. += SPAN_RED("do not")
@@ -32,7 +32,7 @@
if((CS.species_spawn_flags & SPECIES_SPAWN_RESTRICTED) && !(flags & PREF_COPY_TO_NO_CHECK_SPECIES))
errors?.Add(SPAN_WARNING("[CS.name] is a restricted species. You cannot join as this as most normal roles."))
return FALSE
if((CS.species_spawn_flags & SPECIES_SPAWN_WHITELISTED) && !config.check_alien_whitelist(ckey(CS.species_spawn_flags & SPECIES_SPAWN_WHITELIST_FLEXIBLE ? CS.superspecies_id : CS.uid), prefs.client_ckey))
if((CS.species_spawn_flags & SPECIES_SPAWN_WHITELISTED) && !CS.check_whitelist_for_ckey(prefs.client_ckey))
errors?.Add(SPAN_WARNING("You do not have the whitelist to play as a [CS.name]."))
return FALSE
return TRUE

View File

@@ -18,7 +18,7 @@
return TRUE
var/datum/species/CS = character_species_datum()
var/list/whitelisted_ids = CS.get_whitelisted_language_ids() // cache ids from character species for speed
if((L.language_flags & LANGUAGE_WHITELISTED) && !((L.id in whitelisted_ids) || config.check_alien_whitelist(ckey(L.name), client_ckey)))
if((L.language_flags & LANGUAGE_WHITELISTED) && !((L.id in whitelisted_ids) || Configuration.check_language_whitelist(L.id, client_ckey)))
to_chat(user, SPAN_WARNING("[L] is a whitelisted language!"))
return FALSE
var/list/current = get_character_data(CHARACTER_DATA_LANGUAGES)

View File

@@ -10,7 +10,7 @@
* gets list of species we can play of those who are whitelisted
*/
/datum/preferences/proc/resolve_whitelisted_species()
var/list/ids = config.all_alien_whitelists_for(client_ckey)
var/list/ids = Configuration.get_all_species_whitelists_for_ckey(client_ckey)
. = list()
for(var/datum/species/CS as anything in SScharacters.all_character_species())
if((ckey(CS.name) in ids) || (CS.species_spawn_flags & SPECIES_SPAWN_WHITELIST_FLEXIBLE && (ckey(CS.superspecies_id) in ids)))
@@ -20,7 +20,7 @@
* check if we can play a species
*/
/datum/preferences/proc/check_character_species(datum/species/CS)
if((CS.species_spawn_flags & SPECIES_SPAWN_SECRET) && !(config.check_alien_whitelist(ckey(CS.name), client_ckey)))
if((CS.species_spawn_flags & SPECIES_SPAWN_SECRET) && !CS.check_whitelist_for_ckey(client_ckey))
return FALSE
return TRUE

View File

@@ -1081,3 +1081,21 @@ GLOBAL_LIST_INIT(species_oxygen_tank_by_gas, list(
*/
/datum/species/proc/handle_species_job_outfit(var/mob/living/carbon/human/H, var/datum/outfit/outfit)
return
//* Whitelists *//
/**
* Checks if a client is in whitelist.
* * Does not check admin status. You should check yourself.
*/
/datum/species/proc/check_whitelist_for_client(client/user)
return check_whitelist_for_ckey(user.ckey)
/**
* TODO: deprecated. dont' use ckey for auth checks people, use client.
*
* Checks if a ckey is in whitelist.
* * Does not check admin status. You should check yourself.
*/
/datum/species/proc/check_whitelist_for_ckey(ckey)
return Configuration.check_species_whitelist(uid, ckey) || ((species_spawn_flags & SPECIES_SPAWN_WHITELIST_FLEXIBLE) && Configuration.check_species_whitelist(id, ckey))

View File

@@ -0,0 +1,19 @@
# syntax: whitelist.{alien | role |language}.{id} = [
# 'ckey1',
# 'ckey2',
# ]
# DO NOT ACTUALLY PUT ANYONE IN HERE, THIS IS READ BY THE SERVER!
# This should only contain examples, commented out.
whitelist.species.moth_dark = [
# 'silicons',
]
whitelist.language.luinimma = [
# 'silicons',
]
whitelist.role.mime = [
# 'silicons',
]

View File

@@ -1,43 +0,0 @@
some~user - Species
admiraldragon - Vox
aether_elemental - Daemon
arokha - Protean
aruis - Diona
aruis - Xenochimera
azmodan412 - Xenochimera
azmodan412 - Xenomorph Hybrid
bothnevarbackwards - Diona
cameron653 - Xenomorph Hybrid
funnyman2003 - Xenochimera
hawkerthegreat - Vox
inuzari - Diona
jademanique - Xenochimera
jemli - Gutter
ktccd - Diona
mewchild - Diona
mewchild - Vox
natje - Xenochimera
oreganovulgaris - Xenochimera
paradoxspace - Xenochimera
rapidvalj - Vox
rikaru19xjenkins - Xenomorph Hybrid
rikaru19xjenkins - Xenochimera
rixunie - Diona
rixunie - Gutter
seiga - Vox
sepulchre - Vox
sepulchre - Xenomorph Hybrid
silverTalismen - Diona
silverTalismen - Vox
silvertalismen - Xenochimera
singo - Gutter
tastypred - Xenochimera
varonis - Xenochimera
verkister - Xenochimera
xioen - Diona
xioen - Xenochimera
xioen - Xenomorph Hybrid
zammyman215 - Vox
zekesturm - Xenomorph Hybrid
wtfismyname - Xenomorph Hybrid

View File

@@ -1,10 +0,0 @@
# Job whitelist in format ckey - jobname
# Like arokha - clown
seiga - mime
silvertalismen - clown
suicidalpickles - mime
whiskyrose - clown
tinybear16 - clown
chargae - mime
verkister - clown
H0lySquirr3l - clown

1
config/whitelist.toml Normal file
View File

@@ -0,0 +1 @@
# Whitelist file. Loaded second in the load order, after `config.default.toml`.