Another take at a new whitelist system (#8887)

* Another take at a new whitelist system

* fixes

* Fixes usage

* Adds python script to reassemble the glorious new whitelist
This commit is contained in:
Atermonera
2023-03-18 00:13:07 -08:00
committed by GitHub
parent bcc0ecb2a1
commit 2cee4d6a57
10 changed files with 221 additions and 248 deletions
+1 -1
View File
@@ -23,7 +23,7 @@ var/global/jobban_keylist[0] //to store the keys & ranks
if (guest_jobbans(rank))
if(config.guest_jobban && IsGuestKey(M.key))
return "Guest Job-ban"
if(config.usewhitelist && !M.client.is_whitelisted(rank)) // This outright doesn't work, but at least compiles. AFAIK we don't use this system at present. ~Ater
if(config.usewhitelist && !M.client.is_whitelisted(rank))
return "Whitelisted Job"
return ckey_is_jobbanned(M.ckey, rank)
+1 -7
View File
@@ -1944,13 +1944,7 @@
var/client/C = locate(href_list["modify_whitelist"])
if(!istype(C))
return
var/entry = input(usr, "Please enter the path of the whitelist you wish to modify:", "Whitelist target", "") as text|null
if(!entry || !ispath(text2path(entry)))
return
if(href_list["set_value"] == "1")
C.add_whitelist(entry)
else if(href_list["set_value"] == "0")
C.remove_whitelist(entry)
usr.client.admin_modify_whitelist((href_list["set_value"] == "1"), ckey(C.ckey))
/mob/living/proc/can_centcom_reply()
return 0
@@ -78,7 +78,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
// That last list is entirely arbitrary. Take complaints up with Kholdstare.
if((istype(client) && check_rights(R_ADMIN | R_EVENT | R_FUN, 0, client)) || \
(LAZYLEN(instance.species_allowed) && species && (species in instance.species_allowed)) || \
(config.genemod_whitelist && client.is_whitelisted(/whitelist/genemod) && LAZYLEN(instance.whitelist_allowed) && (species in instance.whitelist_allowed)))
(config.genemod_whitelist && client.is_whitelisted("Genemods") && LAZYLEN(instance.whitelist_allowed) && (species in instance.whitelist_allowed)))
.[instance.name] = instance
/datum/category_item/player_setup_item/general/body
+123
View File
@@ -0,0 +1,123 @@
// Rewrites the whitelists to disk
/proc/write_whitelist()
var/filename = "config/whitelists.json"
log_admin("Writing whitelists to disk at `[filename]`")
try
// Byond doesn't have a mechanism for in-place modification of a file, so we have to make a new one and then overwrite the old one.
// If this is interrupted, the .tmp file exists and can be loaded at the start of the next round.
// The in-game list represents the set of valid entries within the whitelist file, so we may as well remove invalid lines in the process.
text2file(json_encode(global.whitelists), filename + ".tmp")
if(fexists(filename) && !fdel(filename))
error("Exception when overwriting whitelist file [filename]")
if(fcopy(filename + ".tmp", filename))
if(!fdel(filename + ".tmp"))
error("Exception when deleting tmp whitelist file [filename].tmp")
catch(var/exception/E)
error("Exception when writing to whitelist file [filename]: [E]")
// Add the selected path to the player's whitelists, if it's valid.
/client/proc/add_whitelist(var/w_key)
if(istype(w_key, /datum))
var/datum/D = w_key
w_key = D:name
if(!istext(w_key))
return FALSE // Not set.
// If they're already whitelisted, do nothing (Also loads the whitelist)
if(is_whitelisted(w_key))
return
log_and_message_admins("[usr ? usr : "SYSTEM"] gave [w_key] whitelist to [src]", usr)
if(!islist(global.whitelists[ckey(ckey)]))
global.whitelists[ckey(ckey)] = list()
global.whitelists[ckey(ckey)] += w_key
write_whitelist()
// Remove the selected path from the player's whitelists.
/client/proc/remove_whitelist(var/w_key)
if(istype(w_key, /datum))
var/datum/D = w_key
w_key = D:name
if(!istext(w_key))
return FALSE // Not set.
// If they're not whitelisted, do nothing (Also loads the whitelist)
if(!is_whitelisted(w_key))
return
log_and_message_admins("[usr ? usr : "SYSTEM"] removed [w_key] whitelist from [src]", usr)
global.whitelists[ckey] -= w_key
write_whitelist()
/client/proc/admin_add_whitelist()
set name = "Whitelist Add Player"
set category = "Admin"
set desc = "Give a whitelist to a target player"
admin_modify_whitelist(TRUE)
/client/proc/admin_del_whitelist()
set name = "Whitelist Remove Player"
set category = "Admin"
set desc = "Remove a whitelist from the target player"
admin_modify_whitelist(FALSE)
/client/proc/admin_modify_whitelist(var/set_value, var/key = null)
if(!check_rights(R_ADMIN|R_DEBUG))
return
// Get the person to whitelist.
if(!key)
key = input(src, "Please enter the CKEY of the player whose whitelist you wish to modify:", "Whitelist ckey", "") as text|null
if(!key || !length(key))
return
key = ckey(key)
// Get the whitelist thing to modify.
var/entry = input(src, "Please enter the name of the whitelist you wish to modify:", "Whitelist target", "") as null|anything in global.whitelistable
if(!entry)
return
if(set_value)
if(!islist(global.whitelists[key]))
global.whitelists[key] = list()
else
to_world("is a list: [global.whitelists[ckey(ckey)]]")
if(entry in global.whitelists[key])
to_chat(src, SPAN_NOTICE("[key] is already whitelisted for [entry]!"))
return
global.whitelists[key] += entry
else
if(!islist(global.whitelists[key]))
to_chat(src, SPAN_NOTICE("[key] isn't whitelisted for anything!"))
return
global.whitelists[key] -= entry
log_and_message_admins("[src] [set_value ? "gave [entry] whitelist to" : "removed [entry] whitelist from"] [key]", src)
write_whitelist()
/client/vv_get_dropdown()
. = ..()
VV_DROPDOWN_OPTION(VV_HK_ADD_WHITELIST, "Add whitelist")
VV_DROPDOWN_OPTION(VV_HK_DEL_WHITELIST, "Remove whitelist")
/client/vv_do_topic(list/href_list)
. = ..()
IF_VV_OPTION(VV_HK_ADD_WHITELIST)
if(!check_rights(R_ADMIN|R_DEBUG))
return
var/client/C = locate(href_list["target"])
if(istype(C))
usr.client.admin_modify_whitelist(TRUE, ckey(C.ckey))
IF_VV_OPTION(VV_HK_DEL_WHITELIST)
if(!check_rights(R_ADMIN|R_DEBUG))
return
var/client/C = locate(href_list["target"])
if(istype(C))
usr.client.admin_modify_whitelist(FALSE, ckey(C.ckey))
-125
View File
@@ -1,125 +0,0 @@
// Rewrites the client's whitelists to disk
/proc/write_whitelist(var/key, var/list/whitelist)
var/filename = "data/player_saves/[copytext(ckey(key),1,2)]/[ckey(key)]/whitelist.json"
log_admin("Writing whitelists to disk for [key] at `[filename]`")
try
// Byond doesn't have a mechanism for in-place modification of a file, so we have to make a new one and then overwrite the old one.
// If this is interrupted, the .tmp file exists and can be loaded at the start of the next round.
// The in-game list represents the set of valid entries within the whitelist file, so we may as well remove invalid lines in the process.
text2file(json_encode(whitelist), filename + ".tmp")
if(fexists(filename) && !fdel(filename))
error("Exception when overwriting whitelist file [filename]")
if(fcopy(filename + ".tmp", filename))
if(!fdel(filename + ".tmp"))
error("Exception when deleting tmp whitelist file [filename].tmp")
catch(var/exception/E)
error("Exception when writing to whitelist file [filename]: [E]")
// Add the selected path to the player's whitelists, if it's valid.
/client/proc/add_whitelist(var/path)
if(istext(path))
path = text2path(path)
if(!ispath(path))
return
// If they're already whitelisted, do nothing (Also loads the whitelist)
if(is_whitelisted(path))
return
log_and_message_admins("[usr ? usr : "SYSTEM"] giving [path] whitelist to [src]", usr)
src.whitelists[path] = TRUE
write_whitelist(src.ckey, src.whitelists)
// Remove the selected path from the player's whitelists.
/client/proc/remove_whitelist(var/path)
if(istext(path))
path = text2path(path)
if(!ispath(path))
return
// If they're not whitelisted, do nothing (Also loads the whitelist)
if(!is_whitelisted(path))
return
log_and_message_admins("[usr ? usr : "SYSTEM"] removing [path] whitelist from [src]", usr)
src.whitelists -= path
write_whitelist(src.ckey, src.whitelists)
/client/proc/admin_add_whitelist()
set name = "Whitelist Add Player"
set category = "Admin"
set desc = "Give a whitelist to a target player"
admin_modify_whitelist(TRUE)
/client/proc/admin_del_whitelist()
set name = "Whitelist Remove Player"
set category = "Admin"
set desc = "Remove a whitelist from the target player"
admin_modify_whitelist(FALSE)
/client/proc/admin_modify_whitelist(var/set_value)
if(!check_rights(R_ADMIN|R_DEBUG))
return
// Get the person to whitelist.
var/key = input(src, "Please enter the CKEY of the player whose whitelist you wish to modify:", "Whitelist ckey", "") as text|null
if(!key || !length(key))
return
key = ckey(key)
if(!fexists("data/player_saves/[copytext(key,1,2)]/[key]/preferences.sav"))
to_chat(src, "That player doesn't seem to exist...")
return
// Get the whitelist thing to modify.
var/entry = input(src, "Please enter the path of the whitelist you wish to modify:", "Whitelist target", "") as text|null
if(!entry || !ispath(text2path(entry)))
return
// If they're logged in, modify it directly.
var/client/C = ckey2client(key)
if(istype(C))
set_value ? C.add_whitelist(entry) : C.remove_whitelist(entry)
return
log_and_message_admins("[src] [set_value ? "giving [entry] whitelist to" : "removing [entry] whitelist from"] [key]", src)
// Else, we have to find and modify the whitelist file ourselves.
var/list/whitelists = load_whitelist(key)
// They're already whitelisted.
if(whitelists[entry] == set_value)
return
whitelists[entry] = set_value
write_whitelist(key, whitelists)
/client/vv_get_dropdown()
. = ..()
VV_DROPDOWN_OPTION(VV_HK_ADD_WHITELIST, "Add whitelist")
VV_DROPDOWN_OPTION(VV_HK_DEL_WHITELIST, "Remove whitelist")
/client/vv_do_topic(list/href_list)
. = ..()
IF_VV_OPTION(VV_HK_ADD_WHITELIST)
if(!check_rights(R_ADMIN|R_DEBUG))
return
var/entry = input(usr, "Please enter the path of the whitelist you wish to add:", "Whitelist target", "") as text|null
if(!entry || !ispath(text2path(entry)))
return
var/client/C = locate(href_list["target"])
if(istype(C))
C.add_whitelist(entry)
IF_VV_OPTION(VV_HK_DEL_WHITELIST)
if(!check_rights(R_ADMIN|R_DEBUG))
return
var/entry = input(usr, "Please enter the path of the whitelist you wish to remove:", "Whitelist target", "") as text|null
if(!entry || !ispath(text2path(entry)))
return
var/client/C = locate(href_list["target"])
if(istype(C))
C.remove_whitelist(entry)
-65
View File
@@ -1,65 +0,0 @@
// Proc to convert the old whitelist systems into the new, shiny, modern system.
// This has to do a lot of file I/O because it handles _everyone's_ whitelists, so it's expected to be pretty expensive.
// Hence, this has to be manually called by an admin.
/proc/load_legacy_whitelist()
var/static/list/alienwhitelist_dict = list(
"Alai" = /datum/language/tajsign,
"Common Skrellian" = /datum/language/skrell,
"Diona" = /datum/species/diona,
"Promethean" = /datum/species/shapeshifter/promethean,
"Schechi" = /datum/language/teshari,
"Siik" = /datum/language/tajaran,
"Sinta'Unathi" = /datum/language/unathi,
"Skrell" = /datum/species/skrell,
"Sol Common" = /datum/language/human,
"Tajara" = /datum/species/tajaran,
"Teshari" = /datum/species/teshari,
"Unathi" = /datum/species/unathi,
"Zaddat" = /datum/species/zaddat,
)
var/list/whitelists_to_write = list()
// Load in the alien whitelists
for(var/line in read_lines("config/alienwhitelist.txt"))
if(!length(line))
continue
var/static/regex/R = regex(" - ")
var/list/tok = splittext(line, R)
// Whitelist is no longer valid.
if(length(tok) < 2 || !(tok[2] in alienwhitelist_dict))
continue
var/key = ckey(tok[1])
// If they don't have a preferences save file, then they probably don't play here any more.
if(!fexists("data/player_saves/[copytext(key,1,2)]/[key]/preferences.sav"))
continue
LAZYADDASSOC(whitelists_to_write[key], alienwhitelist_dict[tok[2]], TRUE)
// Load in the genemod whitelist
for(var/line in read_commentable("config/genemodwhitelist.txt"))
var/key = ckey(line)
// If they don't have a preferences save file, then they probably don't play here any more.
if(!fexists("data/player_saves/[copytext(key,1,2)]/[key]/preferences.sav"))
continue
LAZYADDASSOC(whitelists_to_write[key], /whitelist/genemod, TRUE)
// Write the whitelists to files. Second stage, so we don't make a million individual writes.
for(var/key in whitelists_to_write)
var/filename = "data/player_saves/[copytext(key,1,2)]/[key]/whitelist.json"
var/list/whitelist = whitelists_to_write[key]
try
// If the file already exists, don't just blindly overwrite it.
if(fexists(filename))
var/prior_whitelist = file2text(filename) || ""
if(length(prior_whitelist))
whitelist |= json_decode(prior_whitelist)
text2file(json_encode(whitelist), filename + ".tmp")
if(fexists(filename) && !fdel(filename))
error("Error overwriting whitelist file [filename]")
if(!fcopy(filename + ".tmp", filename) || !fdel(filename + ".tmp"))
error("Exception when deleting tmp whitelist file [filename].tmp")
catch(var/exception/E)
error("Exception when writing to whitelist file [filename]: [E]")
-4
View File
@@ -1,4 +0,0 @@
// This file is reserved for creating paths that can be used to whitelist
// things that aren't directly attributable to specific paths.
/whitelist/genemod // This whitelists a collection of sprite_accessories
var/name = "Genemods"
+36 -42
View File
@@ -1,4 +1,24 @@
/client/var/list/whitelists = null
var/list/whitelists = list()
var/list/whitelistable = list(
SPECIES_DIONA,
SPECIES_PROMETHEAN,
SPECIES_SKRELL,
SPECIES_TAJ,
SPECIES_TESHARI,
SPECIES_UNATHI,
SPECIES_VOX,
SPECIES_ZADDAT,
LANGUAGE_AKHANI,
LANGUAGE_ALAI,
LANGUAGE_SCHECHI,
LANGUAGE_SIIK,
LANGUAGE_SKRELLIAN,
LANGUAGE_SKRELLIANFAR,
LANGUAGE_SOL_COMMON,
LANGUAGE_UNATHI,
LANGUAGE_ZADDAT,
"Genemods",
)
// Prints the client's whitelist entries
@@ -10,58 +30,32 @@
to_chat(src, "You are whitelisted for:")
to_chat(src, jointext(get_whitelists_list(), "\n"))
/client/proc/get_whitelists_list()
. = list()
if(src.whitelists == null)
src.whitelists = load_whitelist(src.ckey)
for(var/key in src.whitelists)
try
. += initial(initial(key:name))
catch()
. += key
return (ckey in global.whitelists) ? global.whitelists[ckey] : list()
/proc/load_whitelist(var/key)
var/filename = "data/player_saves/[copytext(ckey(key),1,2)]/[ckey(key)]/whitelist.json"
var/filename = "config/whitelists.json"
try
// Check the player-specific whitelist file, if it exists.
if(fexists(filename))
// Load the whitelist entries from file, or empty string if empty.`
. = list()
for(var/T in json_decode(file2text(filename) || ""))
T = text2path(T)
if(!ispath(T))
continue
.[T] = TRUE
// Something was removing an entry from the whitelist and interrupted mid-overwrite.
else if(fexists(filename + ".tmp") && fcopy(filename + ".tmp", filename))
. = load_whitelist(key)
if(!fdel(filename + ".tmp"))
error("Exception when deleting tmp whitelist file [filename].tmp")
// Whitelist file doesn't exist, so they aren't whitelisted for anything. Create the file.
else if(fexists("data/player_saves/[copytext(ckey(key),1,2)]/[ckey(key)]/preferences.sav"))
text2file("", filename)
. = list()
global.whitelists = json_decode(file2text(filename) || "")
catch(var/exception/E)
error("Exception when loading whitelist file [filename]: [E]")
// Returns true if the specified path is in the player's whitelists, false otw.
/client/proc/is_whitelisted(var/path)
if(istext(path))
path = text2path(path)
if(!ispath(path))
return
// If it hasn't already been loaded, load it.
if(src.whitelists == null)
src.whitelists = load_whitelist(src.ckey)
return src.whitelists[path]
/client/proc/is_whitelisted(var/w_key)
if(istype(w_key, /datum))
var/datum/D = w_key
w_key = D:name
if(!istext(w_key))
return FALSE // Not set.
return key in global.whitelists[ckey]
/proc/is_alien_whitelisted(mob/M, var/datum/species/species)
/proc/is_alien_whitelisted(mob/M, datum/species/species)
//They are admin or the whitelist isn't in use
if(whitelist_overrides(M))
return TRUE
@@ -75,10 +69,10 @@
return TRUE
var/client/C = (!isclient(M)) ? M.client : M
return C.is_whitelisted(species.type)
return C.is_whitelisted(species.name)
/proc/is_lang_whitelisted(mob/M, var/datum/language/language)
/proc/is_lang_whitelisted(mob/M, datum/language/language)
//They are admin or the whitelist isn't in use
if(whitelist_overrides(M))
return TRUE
@@ -93,7 +87,7 @@
if(!(language.flags & WHITELISTED))
return TRUE
return C.is_whitelisted(language.type)
return C.is_whitelisted(language)
/proc/whitelist_overrides(mob/M)