API Update 2 (#932)

This is another Update to the API that adds / changes:

Unified Naming of API Comands and API Functions. --> They are now called "API Commands" across all files and the DB
Moves API Related procs from world.dm to api.dm
Adds a proc to write the API commands to the db (so there is no need to manually maintain the list of API commands)
The name change needs to be done before the API is live.

No changelog because there is already a entry
This commit is contained in:
Werner
2016-09-17 17:01:02 +02:00
committed by skull132
parent 958d95af06
commit 6bd2247d07
4 changed files with 796 additions and 759 deletions

View File

@@ -19,15 +19,17 @@ CREATE TABLE `ss13_admin_log` (
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `ss13_api_functions` ( CREATE TABLE `ss13_api_commands` (
`id` INT(11) NOT NULL AUTO_INCREMENT, `id` INT(11) NOT NULL AUTO_INCREMENT,
`function` VARCHAR(50) NOT NULL COLLATE 'utf8_bin', `command` VARCHAR(50) NOT NULL COLLATE 'utf8_bin',
`description` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_bin', `description` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_bin',
PRIMARY KEY (`id`) PRIMARY KEY (`id`),
UNIQUE INDEX `UNIQUE command` (`command`)
) )
COLLATE='utf8_bin' COLLATE='utf8_bin'
ENGINE=InnoDB; ENGINE=InnoDB;
CREATE TABLE `ss13_api_tokens` ( CREATE TABLE `ss13_api_tokens` (
`id` INT(11) NOT NULL AUTO_INCREMENT, `id` INT(11) NOT NULL AUTO_INCREMENT,
`token` VARCHAR(100) NOT NULL COLLATE 'utf8_bin', `token` VARCHAR(100) NOT NULL COLLATE 'utf8_bin',
@@ -42,18 +44,19 @@ CREATE TABLE `ss13_api_tokens` (
COLLATE='utf8_bin' COLLATE='utf8_bin'
ENGINE=InnoDB; ENGINE=InnoDB;
CREATE TABLE `ss13_api_token_function` ( CREATE TABLE `ss13_api_token_command` (
`function_id` INT(11) NOT NULL, `command_id` INT(11) NOT NULL,
`token_id` INT(11) NOT NULL, `token_id` INT(11) NOT NULL,
PRIMARY KEY (`function_id`, `token_id`), PRIMARY KEY (`command_id`, `token_id`),
INDEX `token_id` (`token_id`), INDEX `token_id` (`token_id`),
CONSTRAINT `function_id` FOREIGN KEY (`function_id`) REFERENCES `ss13_api_functions` (`id`) ON UPDATE CASCADE ON DELETE CASCADE, CONSTRAINT `function_id` FOREIGN KEY (`command_id`) REFERENCES `ss13_api_commands` (`id`) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT `token_id` FOREIGN KEY (`token_id`) REFERENCES `ss13_api_tokens` (`id`) ON UPDATE CASCADE ON DELETE CASCADE CONSTRAINT `token_id` FOREIGN KEY (`token_id`) REFERENCES `ss13_api_tokens` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
) )
COLLATE='utf8_bin' COLLATE='utf8_bin'
ENGINE=InnoDB; ENGINE=InnoDB;
CREATE TABLE `ss13_ban` ( CREATE TABLE `ss13_ban` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`bantime` datetime NOT NULL, `bantime` datetime NOT NULL,

View File

@@ -12,6 +12,7 @@ var/global/list/silicon_mob_list = list() //List of all silicon mobs, includin
var/global/list/living_mob_list = list() //List of all alive mobs, including clientless. Excludes /mob/new_player var/global/list/living_mob_list = list() //List of all alive mobs, including clientless. Excludes /mob/new_player
var/global/list/dead_mob_list = list() //List of all dead mobs, including clientless. Excludes /mob/new_player var/global/list/dead_mob_list = list() //List of all dead mobs, including clientless. Excludes /mob/new_player
var/global/list/topic_commands = list() //List of all API commands available var/global/list/topic_commands = list() //List of all API commands available
var/global/list/topic_commands_names = list() //List of all API commands available
var/global/list/cable_list = list() //Index for all cables, so that powernets don't have to look through the entire world all the time var/global/list/cable_list = list() //Index for all cables, so that powernets don't have to look through the entire world all the time
var/global/list/chemical_reactions_list //list of all /datum/chemical_reaction datums. Used during chemical reactions var/global/list/chemical_reactions_list //list of all /datum/chemical_reaction datums. Used during chemical reactions

File diff suppressed because it is too large Load Diff

View File

@@ -119,13 +119,27 @@ var/list/world_api_rate_limit = list()
log_debug("API: Request Received - from:[addr], master:[master], key:[key]") log_debug("API: Request Received - from:[addr], master:[master], key:[key]")
diary << "TOPIC: \"[T]\", from:[addr], master:[master], key:[key], auth:[auth] [log_end]" diary << "TOPIC: \"[T]\", from:[addr], master:[master], key:[key], auth:[auth] [log_end]"
if (!ticker) //If the game is not started most API Requests would not work because of the throtteling
response["statuscode"] = 500
response["response"] = "Game not started yet!"
return json_encode(response)
if (isnull(query)) if (isnull(query))
log_debug("API - Bad Request - No query specified") log_debug("API - Bad Request - No query specified")
response["statuscode"] = 400 response["statuscode"] = 400
response["response"] = "Bad Request - No query specified" response["response"] = "Bad Request - No query specified"
return json_encode(response) return json_encode(response)
var/unauthed = do_auth_check(addr,auth,query) var/datum/topic_command/command = topic_commands[query]
//Check if that command exists
if (isnull(command))
log_debug("API: Unknown command called: [query]")
response["statuscode"] = 501
response["response"] = "Not Implemented"
return json_encode(response)
var/unauthed = api_do_auth_check(addr,auth,command)
if (unauthed) if (unauthed)
if (unauthed == 3) if (unauthed == 3)
log_debug("API: Request denied - Auth Service Unavailable") log_debug("API: Request denied - Auth Service Unavailable")
@@ -143,16 +157,7 @@ var/list/world_api_rate_limit = list()
response["response"] = "Bad Auth" response["response"] = "Bad Auth"
return json_encode(response) return json_encode(response)
log_debug("API: Auth valid") log_debug("API: Auth valid")
var/datum/topic_command/command = topic_commands[query]
if (isnull(command))
log_debug("API: Unknown command called: [query]")
response["statuscode"] = 501
response["response"] = "Not Implemented"
return json_encode(response)
if(command.check_params_missing(queryparams)) if(command.check_params_missing(queryparams))
log_debug("API: Mising Params - Status: [command.statuscode] - Response: [command.response]") log_debug("API: Mising Params - Status: [command.statuscode] - Response: [command.response]")
@@ -162,7 +167,7 @@ var/list/world_api_rate_limit = list()
return json_encode(response) return json_encode(response)
else else
command.run_command(queryparams) command.run_command(queryparams)
log_debug("API: Function called: [query] - Status: [command.statuscode] - Response: [command.response]") log_debug("API: Command called: [query] - Status: [command.statuscode] - Response: [command.response]")
response["statuscode"] = command.statuscode response["statuscode"] = command.statuscode
response["response"] = command.response response["response"] = command.response
response["data"] = command.data response["data"] = command.data
@@ -454,47 +459,3 @@ var/inerror = 0
return 1 return 1
#undef FAILED_DB_CONNECTION_CUTOFF #undef FAILED_DB_CONNECTION_CUTOFF
/world/proc/do_auth_check(var/addr, var/auth, var/function)
//Check if rate limited
if(world_api_rate_limit[addr] != null && config.api_rate_limit_whitelist[addr] == null) //Check if the ip is in the rate limiting list and not in the whitelist
if(abs(world_api_rate_limit[addr] - world.time) < config.api_rate_limit) //Check the last request time of the ip
world_api_rate_limit[addr] = world.time // Set the time of the last request
return 2 //Throttled
world_api_rate_limit[addr] = world.time // Set the time of the last request
//Then query for auth
if (!establish_db_connection(dbcon))
return 3 //DB Unavailable
var/DBQuery/authquery = dbcon.NewQuery({"SELECT api_f.function
FROM ss13_api_token_function as api_t_f, ss13_api_tokens as api_t, ss13_api_functions as api_f
WHERE api_t.id = api_t_f.token_id AND api_f.id = api_t_f.function_id
AND api_t.deleted_at IS NULL
AND (
(token = :token AND ip = :ip AND function = :function)
OR
(token = :token AND ip IS NULL AND function = :function)
OR
(token = :token AND ip = :ip AND function = \"ANY\")
OR
(token = :token AND ip IS NULL AND function = \"ANY\")
OR
(token IS NULL AND ip IS NULL AND function = :function)
)"})
//Check if the token is not deleted
//Check if one of the following is true:
// Full Match - Token IP and Function Matches
// Any IP - Token and Function Matches, IP is set to NULL (not required)
// Any Function - Token and IP Matches, Function is set to ANY
// Any Function, Any IP - Token Matches, IP is set to NULL (not required), Function is set to ANY
// Public - Token is set to NULL, IP is set to NULL and function matches
authquery.Execute(list(":token" = auth, ":ip" = addr, ":function" = function))
log_debug("API: Auth Check - Query Executed - Returned Rows: [authquery.RowCount()]")
if (authquery.RowCount())
return 0 // Authed
else
return 1 // Bad Key