From 70923e0c2278128d818c89dcdfbf12e74788d546 Mon Sep 17 00:00:00 2001 From: Heroman3003 <31296024+Heroman3003@users.noreply.github.com> Date: Mon, 12 Dec 2022 05:40:48 +1000 Subject: [PATCH] Adds admin tokens --- code/__defines/admin.dm | 28 +-- code/__defines/procpath.dm | 25 +++ code/_helpers/files.dm | 15 ++ code/_helpers/icons.dm | 181 +++++++++++++++++ code/modules/admin/DB ban/functions.dm | 6 +- code/modules/admin/NewBan.dm | 3 +- code/modules/admin/admin.dm | 190 +++++++++--------- code/modules/admin/admin_report.dm | 8 +- code/modules/admin/holder2.dm | 30 ++- code/modules/admin/newbanjob.dm | 2 +- .../admin/permissionverbs/permissionedit.dm | 14 +- code/modules/admin/player_panel.dm | 22 +- code/modules/admin/topic.dm | 19 ++ code/modules/admin/verbs/adminhelp.dm | 16 +- .../admin/verbs/check_customitem_activity.dm | 2 +- .../admin/view_variables/debug_variables.dm | 4 +- code/modules/admin/view_variables/helpers.dm | 40 ++-- code/modules/mentor/mentorhelp.dm | 12 +- vorestation.dme | 1 + 19 files changed, 445 insertions(+), 173 deletions(-) create mode 100644 code/__defines/procpath.dm diff --git a/code/__defines/admin.dm b/code/__defines/admin.dm index 84e0656c97..0e8730bae8 100644 --- a/code/__defines/admin.dm +++ b/code/__defines/admin.dm @@ -46,26 +46,26 @@ #define SMITE_SPONTANEOUSCOMBUSTION "Spontaneous Combustion" #define SMITE_LIGHTNINGBOLT "Lightning Bolt" -#define ADMIN_QUE(user) "(?)" -#define ADMIN_FLW(user) "(FLW)" -#define ADMIN_PP(user) "(PP)" -#define ADMIN_VV(atom) "(VV)" -#define ADMIN_SM(user) "(SM)" -#define ADMIN_TP(user) "(TP)" -#define ADMIN_BSA(user) "(BSA)" -#define ADMIN_KICK(user) "(KICK)" -#define ADMIN_CENTCOM_REPLY(user) "(RPLY)" -#define ADMIN_SYNDICATE_REPLY(user) "(RPLY)" -#define ADMIN_SC(user) "(SC)" -#define ADMIN_SMITE(user) "(SMITE)" +#define ADMIN_QUE(user) "(?)" +#define ADMIN_FLW(user) "(FLW)" +#define ADMIN_PP(user) "(PP)" +#define ADMIN_VV(atom) "(VV)" +#define ADMIN_SM(user) "(SM)" +#define ADMIN_TP(user) "(TP)" +#define ADMIN_BSA(user) "(BSA)" +#define ADMIN_KICK(user) "(KICK)" +#define ADMIN_CENTCOM_REPLY(user) "(RPLY)" +#define ADMIN_SYNDICATE_REPLY(user) "(RPLY)" +#define ADMIN_SC(user) "(SC)" +#define ADMIN_SMITE(user) "(SMITE)" #define ADMIN_LOOKUP(user) "[key_name_admin(user)][ADMIN_QUE(user)]" #define ADMIN_LOOKUPFLW(user) "[key_name_admin(user)][ADMIN_QUE(user)] [ADMIN_FLW(user)]" #define ADMIN_FULLMONTY_NONAME(user) "[ADMIN_QUE(user)] [ADMIN_PP(user)] [ADMIN_VV(user)] [ADMIN_SM(user)] [ADMIN_FLW(user)] [ADMIN_TP(user)]" #define ADMIN_FULLMONTY(user) "[key_name_admin(user)] [ADMIN_FULLMONTY_NONAME(user)]" -#define ADMIN_JMP(src) "(JMP)" +#define ADMIN_JMP(src) "(JMP)" #define COORD(src) "[src ? "([src.x],[src.y],[src.z])" : "nonexistent location"]" #define ADMIN_COORDJMP(src) "[src ? "[COORD(src)] [ADMIN_JMP(src)]" : "nonexistent location"]" #define AHELP_ACTIVE 1 #define AHELP_CLOSED 2 -#define AHELP_RESOLVED 3 \ No newline at end of file +#define AHELP_RESOLVED 3 diff --git a/code/__defines/procpath.dm b/code/__defines/procpath.dm new file mode 100644 index 0000000000..e58a2a48b2 --- /dev/null +++ b/code/__defines/procpath.dm @@ -0,0 +1,25 @@ +/// Represents a proc or verb path. +/// +/// Despite having no DM-defined static type, proc paths have some variables, +/// listed below. These are not modifiable, but for a given procpath P, +/// `new P(null, "Name", "Desc")` can be used to create a new procpath with the +/// same code but new `name` and `desc` values. The other variables cannot be +/// changed in this way. +/// +/// This type exists only to act as an annotation, providing reasonable static +/// typing for procpaths. Previously, types like `/atom/verb` were used, with +/// the `name` and `desc` vars of `/atom` thus being accessible. Proc and verb +/// paths will fail `istype` and `ispath` checks against `/procpath`. +/procpath + // Although these variables are effectively const, if they are marked const + // below, their accesses are optimized away. + /// A text string of the verb's name. + var/name as text + /// The verb's help text or description. + var/desc as text + /// The category or tab the verb will appear in. + var/category as text + /// Only clients/mobs with `see_invisibility` higher can use the verb. + var/invisibility as num + /// Whether or not the verb appears in statpanel and commandbar when you press space + var/hidden as num diff --git a/code/_helpers/files.dm b/code/_helpers/files.dm index d6603e4275..9468becf8b 100644 --- a/code/_helpers/files.dm +++ b/code/_helpers/files.dm @@ -58,3 +58,18 @@ fileaccess_timer = world.time + FTPDELAY return 0 #undef FTPDELAY + +/// Returns the md5 of a file at a given path. +/proc/md5filepath(path) + . = md5(file(path)) + +/// Save file as an external file then md5 it. +/// Used because md5ing files stored in the rsc sometimes gives incorrect md5 results. +/proc/md5asfile(file) + var/static/notch = 0 + // its importaint this code can handle md5filepath sleeping instead of hard blocking, if it's converted to use rust_g. + var/filename = "tmp/md5asfile.[world.realtime].[world.timeofday].[world.time].[world.tick_usage].[notch]" + notch = WRAP(notch+1, 0, 2**15) + fcopy(file, filename) + . = md5filepath(filename) + fdel(filename) diff --git a/code/_helpers/icons.dm b/code/_helpers/icons.dm index 24f398c8ec..2cb3ef5c69 100644 --- a/code/_helpers/icons.dm +++ b/code/_helpers/icons.dm @@ -502,3 +502,184 @@ GLOBAL_LIST_EMPTY(cached_examine_icons) //Animate it growing animate(img, alpha = 0, transform = matrix()*grow_to, time = anim_duration, loop = loops) + +/// generates a filename for a given asset. +/// like generate_asset_name(), except returns the rsc reference and the rsc file hash as well as the asset name (sans extension) +/// used so that certain asset files dont have to be hashed twice +/proc/generate_and_hash_rsc_file(file, dmi_file_path) + var/rsc_ref = fcopy_rsc(file) + var/hash + //if we have a valid dmi file path we can trust md5'ing the rsc file because we know it doesnt have the bug described in http://www.byond.com/forum/post/2611357 + if(dmi_file_path) + hash = md5(rsc_ref) + else //otherwise, we need to do the expensive fcopy() workaround + hash = md5asfile(rsc_ref) + + return list(rsc_ref, hash, "asset.[hash]") + +///given a text string, returns whether it is a valid dmi icons folder path +/proc/is_valid_dmi_file(icon_path) + if(!istext(icon_path) || !length(icon_path)) + return FALSE + + var/is_in_icon_folder = findtextEx(icon_path, "icons/") + var/is_dmi_file = findtextEx(icon_path, ".dmi") + + if(is_in_icon_folder && is_dmi_file) + return TRUE + return FALSE + +/// given an icon object, dmi file path, or atom/image/mutable_appearance, attempts to find and return an associated dmi file path. +/// a weird quirk about dm is that /icon objects represent both compile-time or dynamic icons in the rsc, +/// but stringifying rsc references returns a dmi file path +/// ONLY if that icon represents a completely unchanged dmi file from when the game was compiled. +/// so if the given object is associated with an icon that was in the rsc when the game was compiled, this returns a path. otherwise it returns "" +/proc/get_icon_dmi_path(icon/icon) + /// the dmi file path we attempt to return if the given object argument is associated with a stringifiable icon + /// if successful, this looks like "icons/path/to/dmi_file.dmi" + var/icon_path = "" + + if(isatom(icon) || istype(icon, /image) || istype(icon, /mutable_appearance)) + var/atom/atom_icon = icon + icon = atom_icon.icon + //atom icons compiled in from 'icons/path/to/dmi_file.dmi' are weird and not really icon objects that you generate with icon(). + //if theyre unchanged dmi's then they're stringifiable to "icons/path/to/dmi_file.dmi" + + if(isicon(icon) && isfile(icon)) + //icons compiled in from 'icons/path/to/dmi_file.dmi' at compile time are weird and arent really /icon objects, + ///but they pass both isicon() and isfile() checks. theyre the easiest case since stringifying them gives us the path we want + var/icon_ref = "\ref[icon]" + var/locate_icon_string = "[locate(icon_ref)]" + + icon_path = locate_icon_string + + else if(isicon(icon) && "[icon]" == "/icon") + // icon objects generated from icon() at runtime are icons, but they ARENT files themselves, they represent icon files. + // if the files they represent are compile time dmi files in the rsc, then + // the rsc reference returned by fcopy_rsc() will be stringifiable to "icons/path/to/dmi_file.dmi" + var/rsc_ref = fcopy_rsc(icon) + + var/icon_ref = "\ref[rsc_ref]" + + var/icon_path_string = "[locate(icon_ref)]" + + icon_path = icon_path_string + + else if(istext(icon)) + var/rsc_ref = fcopy_rsc(icon) + //if its the text path of an existing dmi file, the rsc reference returned by fcopy_rsc() will be stringifiable to a dmi path + + var/rsc_ref_ref = "\ref[rsc_ref]" + var/rsc_ref_string = "[locate(rsc_ref_ref)]" + + icon_path = rsc_ref_string + + if(is_valid_dmi_file(icon_path)) + return icon_path + + return FALSE + +/** + * generate an asset for the given icon or the icon of the given appearance for [thing], and send it to any clients in target. + * Arguments: + * * thing - either a /icon object, or an object that has an appearance (atom, image, mutable_appearance). + * * target - either a reference to or a list of references to /client's or mobs with clients + * * icon_state - string to force a particular icon_state for the icon to be used + * * dir - dir number to force a particular direction for the icon to be used + * * frame - what frame of the icon_state's animation for the icon being used + * * moving - whether or not to use a moving state for the given icon + * * sourceonly - if TRUE, only generate the asset and send back the asset url, instead of tags that display the icon to players + * * extra_clases - string of extra css classes to use when returning the icon string + */ +/proc/icon2html(atom/thing, client/target, icon_state, dir = SOUTH, frame = 1, moving = FALSE, sourceonly = FALSE, extra_classes = null) + if (!thing) + return + //if(SSlag_switch.measures[DISABLE_USR_ICON2HTML] && usr && !HAS_TRAIT(usr, TRAIT_BYPASS_MEASURES)) + //return + + var/key + var/icon/icon2collapse = thing + + if (!target) + return + if (target == world) + target = GLOB.clients + + var/list/targets + if (!islist(target)) + targets = list(target) + else + targets = target + if(!length(targets)) + return + + //check if the given object is associated with a dmi file in the icons folder. if it is then we dont need to do a lot of work + //for asset generation to get around byond limitations + var/icon_path = get_icon_dmi_path(thing) + + if (!isicon(icon2collapse)) + if (isfile(thing)) //special snowflake + //var/name = SANITIZE_FILENAME("[generate_asset_name(thing)].png") + var/name = "[generate_asset_name(thing)].png" + if (!SSassets.cache[name]) + register_asset(name, thing) + for (var/thing2 in targets) + send_asset(thing2, name) + if(sourceonly) + return get_asset_url(name) + return "" + + //its either an atom, image, or mutable_appearance, we want its icon var + icon2collapse = thing.icon + + if (isnull(icon_state)) + icon_state = thing.icon_state + //Despite casting to atom, this code path supports mutable appearances, so let's be nice to them + //if(isnull(icon_state) || (isatom(thing) && thing.flags_1 & HTML_USE_INITAL_ICON_1)) + if(isnull(icon_state) || isatom(thing)) + icon_state = initial(thing.icon_state) + if (isnull(dir)) + dir = initial(thing.dir) + + if (isnull(dir)) + dir = thing.dir + + if (ishuman(thing)) // Shitty workaround for a BYOND issue. + var/icon/temp = icon2collapse + icon2collapse = icon() + icon2collapse.Insert(temp, dir = SOUTH) + dir = SOUTH + else + if (isnull(dir)) + dir = SOUTH + if (isnull(icon_state)) + icon_state = "" + + icon2collapse = icon(icon2collapse, icon_state, dir, frame, moving) + + var/list/name_and_ref = generate_and_hash_rsc_file(icon2collapse, icon_path)//pretend that tuples exist + + var/rsc_ref = name_and_ref[1] //weird object thats not even readable to the debugger, represents a reference to the icons rsc entry + var/file_hash = name_and_ref[2] + key = "[name_and_ref[3]].png" + + if(!SSassets.cache[key]) + register_asset(key, rsc_ref, file_hash, icon_path) + for (var/client_target in targets) + send_asset(client_target, key) + if(sourceonly) + return get_asset_url(key) + return "" + +//Costlier version of icon2html() that uses getFlatIcon() to account for overlays, underlays, etc. Use with extreme moderation, ESPECIALLY on mobs. +/proc/costly_icon2html(thing, target, sourceonly = FALSE) + if (!thing) + return + //if(SSlag_switch.measures[DISABLE_USR_ICON2HTML] && usr && !HAS_TRAIT(usr, TRAIT_BYPASS_MEASURES)) + //return + + if (isicon(thing)) + return icon2html(thing, target) + + var/icon/I = getFlatIcon(thing) + return icon2html(I, target, sourceonly = sourceonly) diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/DB ban/functions.dm index 9c25b4f1e5..fe05157bc4 100644 --- a/code/modules/admin/DB ban/functions.dm +++ b/code/modules/admin/DB ban/functions.dm @@ -444,7 +444,7 @@ if("PERMABAN") typedesc = "PERMABAN" if("TEMPBAN") - typedesc = "TEMPBAN
([duration] minutes) [(unbanned || auto) ? "" : "(Edit)"]
Expires [expiration]
" + typedesc = "TEMPBAN
([duration] minutes) [(unbanned || auto) ? "" : "(Edit)"]
Expires [expiration]
" if("JOB_PERMABAN") typedesc = "JOBBAN
([job])" if("JOB_TEMPBAN") @@ -455,14 +455,14 @@ output += "[ckey]" output += "[bantime]" output += "[ackey]" - output += "[(unbanned || auto) ? "" : "Unban"]" + output += "[(unbanned || auto) ? "" : "Unban"]" output += "" output += "" output += "IP: [ip]" output += "CIP: [cid]" output += "" output += "" - output += "Reason: [(unbanned || auto) ? "" : "(Edit)"] \"[reason]\"" + output += "Reason: [(unbanned || auto) ? "" : "(Edit)"] \"[reason]\"" output += "" if(edits) output += "" diff --git a/code/modules/admin/NewBan.dm b/code/modules/admin/NewBan.dm index 15d29eb1f0..22e8d9a4b2 100644 --- a/code/modules/admin/NewBan.dm +++ b/code/modules/admin/NewBan.dm @@ -186,7 +186,7 @@ var/savefile/Banlist if(!expiry) expiry = "Removal Pending" else expiry = "Permaban" - dat += text("(U)(E) Key: [key]ComputerID: [id]IP: [ip] [expiry](By: [by])(Reason: [reason])") + dat += text("(U)(E) Key: [key]ComputerID: [id]IP: [ip] [expiry](By: [by])(Reason: [reason])") dat += "" dat = "
Bans: (U) = Unban , (E) = Edit Ban - ([count] Bans)
[dat]" @@ -227,4 +227,3 @@ var/savefile/Banlist Banlist.cd = "/base" for (var/A in Banlist.dir) RemoveBan(A) - diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index ebbece968d..f2f746323f 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -43,12 +43,12 @@ var/global/floorIsLava = 0 body += "Options panel for [M]" if(M.client) body += " played by [M.client] " - body += "\[[M.client.holder ? M.client.holder.rank : "Player"]\]" + body += "\[[M.client.holder ? M.client.holder.rank : "Player"]\]" if(istype(M, /mob/new_player)) body += " Hasn't Entered Game " else - body += " \[Heal\] " + body += " \[Heal\] " if(M.client) body += "
First connection: [M.client.player_age] days ago" @@ -57,41 +57,41 @@ var/global/floorIsLava = 0 body += {"

\[ - VV - - TP - - PM - - SM - + VV - + TP - + PM - + SM - [admin_jump_link(M, src)]\]
Mob type: [M.type]
Inactivity time: [M.client ? "[M.client.inactivity/600] minutes" : "Logged out"]

- Kick | - Warn | - Ban | - Jobban | - Notes + Kick | + Warn | + Ban | + Jobban | + Notes "} if(M.client) - body += "| Prison | " - body += "\ Send back to Lobby | " + body += "| Prison | " + body += "\ Send back to Lobby | " var/muted = M.client.prefs.muted body += {"
Mute: - \[IC | - OOC | - PRAY | - ADMINHELP | - DEADCHAT\] - (toggle all) + \[IC | + OOC | + PRAY | + ADMINHELP | + DEADCHAT\] + (toggle all) "} body += {"

- Jump to | - Get | - Send To + Jump to | + Get | + Send To

- [check_rights(R_ADMIN|R_MOD|R_EVENT,0) ? "Traitor panel | " : "" ] - Narrate to | - Subtle message + [check_rights(R_ADMIN|R_MOD|R_EVENT,0) ? "Traitor panel | " : "" ] + Narrate to | + Subtle message "} if (M.client) @@ -104,30 +104,30 @@ var/global/floorIsLava = 0 if(issmall(M)) body += "Monkeyized | " else - body += "Monkeyize | " + body += "Monkeyize | " //Corgi if(iscorgi(M)) body += "Corgized | " else - body += "Corgize | " + body += "Corgize | " //AI / Cyborg if(isAI(M)) body += "Is an AI " else if(ishuman(M)) - body += {"Make AI | - Make Robot | - Make Alien + body += {"Make AI | + Make Robot | + Make Alien "} //Simple Animals if(isanimal(M)) - body += "Re-Animalize | " + body += "Re-Animalize | " else - body += "Animalize | " + body += "Animalize | " - body += "Respawn | " + body += "Respawn | " // DNA2 - Admin Hax if(M.dna && iscarbon(M)) @@ -142,7 +142,7 @@ var/global/floorIsLava = 0 if(bname) var/bstate=M.dna.GetSEState(block) var/bcolor="[(bstate)?"#006600":"#ff0000"]" - body += "[bname][block]" + body += "[bname][block]" else body += "[block]" body+="" @@ -150,45 +150,45 @@ var/global/floorIsLava = 0 body += {"

Rudimentary transformation:
These transformations only create a new mob type and copy stuff over. They do not take into account MMIs and similar mob-specific things. The buttons in 'Transformations' are preferred, when possible.

- Observer | - \[ Xenos: Larva - Drone - Hunter - Sentinel - Queen \] | - \[ Crew: Human - Unathi - Tajaran - Skrell \] | \[ - Nymph - Diona \] | - \[ slime: Baby, - Adult \] - Monkey | - Cyborg | - Cat | - Runtime | - Corgi | - Ian | - Crab | - Coffee | - \[ Construct: Armoured , - Builder , - Wraith \] - Shade + Observer | + \[ Xenos: Larva + Drone + Hunter + Sentinel + Queen \] | + \[ Crew: Human + Unathi + Tajaran + Skrell \] | \[ + Nymph + Diona \] | + \[ slime: Baby, + Adult \] + Monkey | + Cyborg | + Cat | + Runtime | + Corgi | + Ian | + Crab | + Coffee | + \[ Construct: Armoured , + Builder , + Wraith \] + Shade
"} body += {"

Other actions:
- Forcesay + Forcesay "} if (M.client) body += {" | - Thunderdome 1 | - Thunderdome 2 | - Thunderdome Admin | - Thunderdome Observer | + Thunderdome 1 | + Thunderdome 2 | + Thunderdome Admin | + Thunderdome Observer | "} // language toggles body += "

Languages:
" @@ -199,9 +199,9 @@ var/global/floorIsLava = 0 if(!f) body += " | " else f = 0 if(L in M.languages) - body += "[k]" + body += "[k]" else - body += "[k]" + body += "[k]" body += {"
@@ -527,7 +527,7 @@ var/global/floorIsLava = 0 var/r = t if( findtext(r,"##") ) r = copytext( r, 1, findtext(r,"##") )//removes the description - dat += text("") + dat += text("") dat += "
[t] (unban)
[t] (unban)
" usr << browse(dat, "window=ban;size=400x400") @@ -536,20 +536,20 @@ var/global/floorIsLava = 0 var/dat = {"
Game Panel

\n - Change Game Mode
+ Change Game Mode
"} if(master_mode == "secret") - dat += "(Force Secret Mode)
" + dat += "(Force Secret Mode)
" dat += {"
- Create Object
- Quick Create Object
- Create Turf
- Create Mob
-
Edit Airflow Settings
- Edit Phoron Settings
- Choose a default ZAS setting
+ Create Object
+ Quick Create Object
+ Create Turf
+ Create Mob
+
Edit Airflow Settings
+ Edit Phoron Settings
+ Choose a default ZAS setting
"} usr << browse(dat, "window=admin2;size=210x280") @@ -563,7 +563,7 @@ var/global/floorIsLava = 0 for(var/datum/admin_secret_category/category in admin_secrets.categories) if(!category.can_view(usr)) continue - dat += "[category.name] " + dat += "[category.name] " dat += "
" // If a category is selected, print its description and then options @@ -574,7 +574,7 @@ var/global/floorIsLava = 0 for(var/datum/admin_secret_item/item in active_category.items) if(!item.can_view(usr)) continue - dat += "[item.name()]
" + dat += "[item.name()]
" dat += "
" var/datum/browser/popup = new(usr, "secrets", "Secrets", 500, 500) @@ -1168,34 +1168,34 @@ var/datum/announcement/minor/admin_min_announcer = new out += "
" if(ticker.mode.ert_disabled) - out += "Emergency Response Teams: disabled" + out += "Emergency Response Teams: disabled" else - out += "Emergency Response Teams: enabled" + out += "Emergency Response Teams: enabled" out += "
" if(ticker.mode.deny_respawn) - out += "Respawning: disallowed" + out += "Respawning: disallowed" else - out += "Respawning: allowed" + out += "Respawning: allowed" out += "
" - out += "Shuttle delay multiplier: [ticker.mode.shuttle_delay]
" + out += "Shuttle delay multiplier: [ticker.mode.shuttle_delay]
" if(ticker.mode.auto_recall_shuttle) - out += "Shuttle auto-recall: enabled" + out += "Shuttle auto-recall: enabled" else - out += "Shuttle auto-recall: disabled" + out += "Shuttle auto-recall: disabled" out += "

" if(ticker.mode.event_delay_mod_moderate) - out += "Moderate event time modifier: [ticker.mode.event_delay_mod_moderate]
" + out += "Moderate event time modifier: [ticker.mode.event_delay_mod_moderate]
" else - out += "Moderate event time modifier: unset
" + out += "Moderate event time modifier: unset
" if(ticker.mode.event_delay_mod_major) - out += "Major event time modifier: [ticker.mode.event_delay_mod_major]
" + out += "Major event time modifier: [ticker.mode.event_delay_mod_major]
" else - out += "Major event time modifier: unset
" + out += "Major event time modifier: unset
" out += "
" @@ -1212,7 +1212,7 @@ var/datum/announcement/minor/admin_min_announcer = new out += " (not currently scaling, set a coefficient)" out += "
" else - out += "Autotraitor disabled.
" + out += "Autotraitor disabled.
" out += "All antag ids:" if(ticker.mode.antag_templates && ticker.mode.antag_templates.len) @@ -1220,10 +1220,10 @@ var/datum/announcement/minor/admin_min_announcer = new antag.update_current_antag_max() out += " [antag.id]" out += " ([antag.get_antag_count()]/[antag.cur_max]) " - out += " \[-\]
" + out += " \[-\]
" else out += " None." - out += " \[+\]
" + out += " \[+\]
" usr << browse(out, "window=edit_mode[src]") feedback_add_details("admin_verb","SGM") @@ -1559,12 +1559,12 @@ var/datum/announcement/minor/admin_min_announcer = new log_admin("[key_name(src.owner)] replied to a fax message from [key_name(P.sender)]") for(var/client/C in GLOB.admins) if((R_ADMIN | R_MOD | R_EVENT) & C.holder.rights) - to_chat(C, "FAX LOG:[key_name_admin(src.owner)] replied to a fax message from [key_name_admin(P.sender)] (VIEW)") + to_chat(C, "FAX LOG:[key_name_admin(src.owner)] replied to a fax message from [key_name_admin(P.sender)] (VIEW)") else log_admin("[key_name(src.owner)] has sent a fax message to [destination.department]") for(var/client/C in GLOB.admins) if((R_ADMIN | R_MOD | R_EVENT) & C.holder.rights) - to_chat(C, "FAX LOG:[key_name_admin(src.owner)] has sent a fax message to [destination.department] (VIEW)") + to_chat(C, "FAX LOG:[key_name_admin(src.owner)] has sent a fax message to [destination.department] (VIEW)") var/plaintext_title = P.sender ? "replied to [key_name(P.sender)]'s fax" : "sent a fax message to [destination.department]" var/fax_text = paper_html_to_plaintext(P.info) diff --git a/code/modules/admin/admin_report.dm b/code/modules/admin/admin_report.dm index bc1adbcfdc..e0af36c9c8 100644 --- a/code/modules/admin/admin_report.dm +++ b/code/modules/admin/admin_report.dm @@ -107,9 +107,9 @@ world/New() output += "Offense:[N.body]
" output += "Occured at [time2text(N.date,"MM/DD hh:mm:ss")]
" output += "authored by [N.author]
" - output += " Flag as Handled" + output += " Flag as Handled" if(src.key == N.author) - output += " Edit" + output += " Edit" output += "
" output += "
" else @@ -149,7 +149,7 @@ world/New() for(var/datum/admin_report/N in reports) if(N.ID == ID) found = N - if(!found) + if(!found) to_chat(src, "* An error occured, sorry.") found.done = 1 @@ -171,7 +171,7 @@ world/New() for(var/datum/admin_report/N in reports) if(N.ID == ID) found = N - if(!found) + if(!found) to_chat(src, "* An error occured, sorry.") var/body = tgui_input_text(src.mob, "Enter a body for the news", "Body", multiline = TRUE, prevent_enter = TRUE) diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm index cff69baffc..46544a0809 100644 --- a/code/modules/admin/holder2.dm +++ b/code/modules/admin/holder2.dm @@ -1,3 +1,6 @@ +GLOBAL_VAR_INIT(href_token, GenerateToken()) +GLOBAL_PROTECT(href_token) + var/list/admin_datums = list() /datum/admins @@ -13,6 +16,8 @@ var/list/admin_datums = list() var/datum/feed_channel/admincaster_feed_channel = new /datum/feed_channel var/admincaster_signature //What you'll sign the newsfeeds as + var/href_token + /datum/admins/New(initial_rank = "Temporary Admin", initial_rights = 0, ckey) if(!ckey) @@ -20,6 +25,7 @@ var/list/admin_datums = list() qdel(src) return admincaster_signature = "[using_map.company_name] Officer #[rand(0,9)][rand(0,9)][rand(0,9)]" + href_token = GenerateToken() rank = initial_rank rights = initial_rights admin_datums[ckey] = src @@ -126,4 +132,26 @@ NOTE: It checks usr by default. Supply the "user" argument if you wish to check if(rights_required && !(rights_required & subject.holder.rights)) return 0 return 1 - return 0 \ No newline at end of file + return 0 + +/proc/GenerateToken() + . = "" + for(var/I in 1 to 32) + . += "[rand(10)]" + +/proc/RawHrefToken(forceGlobal = FALSE) + var/tok = GLOB.href_token + if(!forceGlobal && usr) + var/client/C = usr.client + if(!C) + CRASH("No client for HrefToken()!") + var/datum/admins/holder = C.holder + if(holder) + tok = holder.href_token + return tok + +/proc/HrefToken(forceGlobal = FALSE) + return "admin_token=[RawHrefToken(forceGlobal)]" + +/proc/HrefTokenFormField(forceGlobal = FALSE) + return "" diff --git a/code/modules/admin/newbanjob.dm b/code/modules/admin/newbanjob.dm index c7180d0a49..e743bb6bc2 100644 --- a/code/modules/admin/newbanjob.dm +++ b/code/modules/admin/newbanjob.dm @@ -211,7 +211,7 @@ var/savefile/Banlistjob for (var/A in Banlistjob.dir) count++ Banlistjob.cd = "/base/[A]" - dat += text("(U) Key: [Banlistjob["key"]] Rank: [Banlistjob["rank"]] ([Banlistjob["temp"] ? "[GetBanExpjob(Banlistjob["minutes"]) ? GetBanExpjob(Banlistjob["minutes"]) : "Removal pending" ]" : "Permaban"])(By: [Banlistjob["bannedby"]])(Reason: [Banlistjob["reason"]])") + dat += text("(U) Key: [Banlistjob["key"]] Rank: [Banlistjob["rank"]] ([Banlistjob["temp"] ? "[GetBanExpjob(Banlistjob["minutes"]) ? GetBanExpjob(Banlistjob["minutes"]) : "Removal pending" ]" : "Permaban"])(By: [Banlistjob["bannedby"]])(Reason: [Banlistjob["reason"]])") dat += "" dat = "
Bans: (U) = Unban , - ([count] Bans)
[dat]" diff --git a/code/modules/admin/permissionverbs/permissionedit.dm b/code/modules/admin/permissionverbs/permissionedit.dm index 549f537d67..dd2e8a2511 100644 --- a/code/modules/admin/permissionverbs/permissionedit.dm +++ b/code/modules/admin/permissionverbs/permissionedit.dm @@ -18,7 +18,7 @@
- + "} @@ -31,9 +31,9 @@ if(!rights) rights = "*none*" output += "" - output += "" - output += "" - output += "" + output += "" + output += "" + output += "" output += "" output += {" @@ -153,5 +153,9 @@ qdel(insert_query) //CHOMPEdit TGSQL var/DBQuery/log_query = SSdbcore.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]')") //CHOMPEdit TGSQL log_query.Execute() +<<<<<<< HEAD qdel(log_query) //CHOMPEdit TGSQL - to_chat(usr, "Permission added.") \ No newline at end of file + to_chat(usr, "Permission added.") +======= + to_chat(usr, "Permission added.") +>>>>>>> 3537c20742... Merge pull request #14188 from ItsSelis/selis-admin-tokens diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index cf50b20ee0..3f335058e4 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -75,13 +75,13 @@ body += "
CKEY \[+\]CKEY \[+\] RANKPERMISSIONS
[adm_ckey] \[-\][rank][rights][adm_ckey] \[-\][rank][rights]
"; - body += "PP - " - body += "N - " + body += "PP - " + body += "N - " body += "VV - " - body += "TP - " - body += "PM - " - body += "SM - " - body += "JMP
" + body += "TP - " + body += "PM - " + body += "SM - " + body += "JMP
" if(antagonist > 0) body += "Antagonist"; @@ -389,21 +389,21 @@ dat += "Round Duration: [roundduration2text()]
" dat += "Emergency shuttle
" if (!emergency_shuttle.online()) - dat += "Call Shuttle
" + dat += "Call Shuttle
" else if (emergency_shuttle.wait_for_launch) var/timeleft = emergency_shuttle.estimate_launch_time() - dat += "ETL: [(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]
" + dat += "ETL: [(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]
" else if (emergency_shuttle.shuttle.has_arrive_time()) var/timeleft = emergency_shuttle.estimate_arrival_time() - dat += "ETA: [(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]
" - dat += "Send Back
" + dat += "ETA: [(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]
" + dat += "Send Back
" if (emergency_shuttle.shuttle.moving_status == SHUTTLE_WARMUP) dat += "Launching now..." - dat += "[ticker.delay_end ? "End Round Normally" : "Delay Round End"]
" + dat += "[ticker.delay_end ? "End Round Normally" : "Delay Round End"]
" dat += "
" for(var/antag_type in all_antag_types) var/datum/antagonist/A = all_antag_types[antag_type] diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index d17219e59c..2ba771a67a 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1,3 +1,19 @@ +/datum/admins/proc/CheckAdminHref(href, href_list) + var/auth = href_list["admin_token"] + . = auth && (auth == href_token || auth == GLOB.href_token) + if(.) + return + var/msg = !auth ? "no" : "a bad" + message_admins("[key_name_admin(usr)] clicked an href with [msg] authorization key!") + + var/debug_admin_hrefs = TRUE // Remove once everything is converted over + if(debug_admin_hrefs) + message_admins("Debug mode enabled, call not blocked. Please ask your coders to review this round's logs.") + log_world("UAH: [href]") + return TRUE + + log_admin("[key_name(usr)] clicked an href with [msg] authorization key! [href]") + /datum/admins/Topic(href, href_list) ..() @@ -6,6 +22,9 @@ message_admins("[usr.key] has attempted to override the admin panel!") return + if(!CheckAdminHref(href, href_list)) + return + if(ticker.mode && ticker.mode.check_antagonists_topic(href, href_list)) check_antagonists() return diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 77ab40adc1..1209f5fbac 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -81,9 +81,9 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) if(!l2b) return var/list/dat = list("[title]") - dat += "Refresh

" + dat += "Refresh

" for(var/datum/admin_help/AH as anything in l2b) - dat += "Ticket #[AH.id]: [AH.initiator_key_name]: [AH.name]
" + dat += "Ticket #[AH.id]: [AH.initiator_key_name]: [AH.name]
" usr << browse(dat.Join(), "window=ahelp_list[state];size=600x480") @@ -250,11 +250,11 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) /datum/admin_help/proc/ClosureLinks(ref_src) if(!ref_src) ref_src = "\ref[src]" - . = " (REJT)" - . += " (IC)" - . += " (CLOSE)" - . += " (RSLVE)" - . += " (HANDLE)" + . = " (REJT)" + . += " (IC)" + . += " (CLOSE)" + . += " (RSLVE)" + . += " (HANDLE)" //private /datum/admin_help/proc/LinkedReplyName(ref_src) @@ -266,7 +266,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) /datum/admin_help/proc/TicketHref(msg, ref_src, action = "ticket") if(!ref_src) ref_src = "\ref[src]" - return "[msg]" + return "[msg]" //message from the initiator without a target, all admins will see this //won't bug irc diff --git a/code/modules/admin/verbs/check_customitem_activity.dm b/code/modules/admin/verbs/check_customitem_activity.dm index eb1879e656..086b6c410c 100644 --- a/code/modules/admin/verbs/check_customitem_activity.dm +++ b/code/modules/admin/verbs/check_customitem_activity.dm @@ -19,7 +19,7 @@ var/inactive_keys = "None
" dat += "
" dat += "This system was implemented on March 1 2013, and the database a few days before that. Root server access is required to add or disable access to specific custom items.
" else - dat += "Populate list (requires an active database connection)
" + dat += "Populate list (requires an active database connection)
" usr << browse(dat, "window=inactive_customitems;size=600x480") diff --git a/code/modules/admin/view_variables/debug_variables.dm b/code/modules/admin/view_variables/debug_variables.dm index 97ce67e61b..6f401f0185 100644 --- a/code/modules/admin/view_variables/debug_variables.dm +++ b/code/modules/admin/view_variables/debug_variables.dm @@ -8,9 +8,9 @@ name = DA[name] //name is really the index until this line else value = DA[name] - header = "
  • (E) (C) (-) " + header = "
  • (E) (C) (-) " else - header = "
  • (E) (C) (M) " + header = "
  • (E) (C) (M) " else header = "
  • " diff --git a/code/modules/admin/view_variables/helpers.dm b/code/modules/admin/view_variables/helpers.dm index e9d9337cf4..caf44a2d30 100644 --- a/code/modules/admin/view_variables/helpers.dm +++ b/code/modules/admin/view_variables/helpers.dm @@ -35,14 +35,14 @@ /mob/get_view_variables_options() return ..() + {" - + - - - - - - + + + + + + @@ -51,26 +51,26 @@ - - - - + + + + - - + + - + "} /mob/living/carbon/human/get_view_variables_options() return ..() + {" - - - - - + + + + + "} /obj/get_view_variables_options() @@ -188,4 +188,4 @@ /proc/forbidden_varedit_object_types() return list( /datum/admins //Admins editing their own admin-power object? Yup, sounds like a good idea. - ) \ No newline at end of file + ) diff --git a/code/modules/mentor/mentorhelp.dm b/code/modules/mentor/mentorhelp.dm index e5f7ac49d8..6e0372c6e8 100644 --- a/code/modules/mentor/mentorhelp.dm +++ b/code/modules/mentor/mentorhelp.dm @@ -53,9 +53,9 @@ GLOBAL_DATUM_INIT(mhelp_tickets, /datum/mentor_help_tickets, new) if(!l2b) return var/list/dat = list("[title]") - dat += "Refresh

    " + dat += "Refresh

    " for(var/datum/mentor_help/MH as anything in l2b) - dat += "Ticket #[MH.id]: [MH.initiator_ckey]: [MH.name]
    " + dat += "Ticket #[MH.id]: [MH.initiator_ckey]: [MH.name]
    " usr << browse(dat.Join(), "window=mhelp_list[state];size=600x480") @@ -173,24 +173,24 @@ GLOBAL_DATUM_INIT(mhelp_tickets, /datum/mentor_help_tickets, new) /datum/mentor_help/proc/ClosureLinks(ref_src) if(!ref_src) ref_src = "\ref[src]" - . = " (RSLVE)" + . = " (RSLVE)" //private /datum/mentor_help/proc/LinkedReplyName(ref_src) if(!ref_src) ref_src = "\ref[src]" - return "[initiator_ckey]" + return "[initiator_ckey]" //private /datum/mentor_help/proc/TicketHref(msg, ref_src, action = "ticket") if(!ref_src) ref_src = "\ref[src]" - return "[msg]" + return "[msg]" //message from the initiator without a target, all people with mentor powers will see this /datum/mentor_help/proc/MessageNoRecipient(msg) var/ref_src = "\ref[src]" - var/chat_msg = "(ESCALATE) Ticket [TicketHref("#[id]", ref_src)]: [LinkedReplyName(ref_src)]: [msg]" + var/chat_msg = "(ESCALATE) Ticket [TicketHref("#[id]", ref_src)]: [LinkedReplyName(ref_src)]: [msg]" AddInteraction("[LinkedReplyName(ref_src)]: [msg]") for (var/client/C in GLOB.mentors) if (C.is_preference_enabled(/datum/client_preference/play_mentorhelp_ping)) diff --git a/vorestation.dme b/vorestation.dme index 9341f6948d..fbd59d88ca 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -82,6 +82,7 @@ #include "code\__defines\plants.dm" #include "code\__defines\preferences.dm" #include "code\__defines\process_scheduler.dm" +#include "code\__defines\procpath.dm" #include "code\__defines\qdel.dm" #include "code\__defines\research.dm" #include "code\__defines\roguemining_vr.dm"