-
-
Notifications
You must be signed in to change notification settings - Fork 78
The Scrummage API
Support for using and integrating with the Scrummage API is provided for tier 3 and 4 monthly sponsors, and ad-hoc support is provided based on the relevant time-limit. For more details, you can contact us via the sponsors page.
A new API has been developed for Scrummage (Effective since Version 2) which currently allows users to read information. This API uses JSON Web Tokens (JWTs) for authorisation for the API.
The /api/auth endpoint is used to retrieve either an existing or new JSON Web Token, that can be used for all other requests. JSON Web Tokens can be verified at jwt.io.
To authenticate to this the following data needs to be supplied in the body of the POST request:
{
"Username": "YOUR USERNAME GOES HERE",
"Password": "YOUR PASSWORD GOES HERE"
}You can also get your JWT by logging into Scrummage, going to the Account page, and selecting the copy to clipboard icon at the top of the screen, next to "Your API Key".
Following the /api/auth endpoint method, if the authentication is successful, you will receive a JWT in a format similar to below:
{
"API Key": "YOUR.JWT.TOKEN",
"Message": "Registration successful. Welcome [YOUR USERNAME]."
}For the rest of the endpoints, you will need to supply your JWT using the "Authorization" header in any HTTP request as shown below:
Authorization: Bearer YOUR.JWT.TOKENFull List of API Endpoints
The following JSON lists all endpoints and their relevant information:
{
"Endpoints": {
"API": {
"GET": {
"Admin rights required": false,
"Endpoint Checking": "/api/endpoints"
}
},
"Authentication": {
"POST": {
"Obtain API Key": {
"Admin rights required": false,
"Endpoint": "/api/auth",
"Fields": {
"Password": {
"Attributes": {
"Required": true,
"Type": "String"
}
},
"Username": {
"Attributes": {
"Required": true,
"Type": "String"
}
}
}
}
}
},
"Dashboard": {
"GET": {
"Retrieve dashboard statistics": {
"Admin rights required": false,
"Endpoint": "api/dashboard"
}
}
},
"Events": {
"GET": {
"Retrieve account data": {
"Admin rights required": false,
"Endpoint": "/api/events",
"Optional Search Filters": {
"Created At": "String - Timestamp",
"Description": "String",
"ID": "Integer"
}
}
}
},
"Identity Management": {
"GET": {
"POST": {
"Create new identity": {
"Admin rights required": true,
"Endpoint": "/api/identity/new",
"Fields": {
"Email": {
"Attributes": {
"Required": true,
"Type": "String"
}
},
"First": {
"Attributes": {
"Required": true,
"Type": "String"
}
},
"Middle": {
"Attributes": {
"Required": false,
"Type": "String"
}
},
"Phone": {
"Attributes": {
"Required": true,
"Type": "String"
}
},
"Surname": {
"Attributes": {
"Required": true,
"Type": "String"
}
},
"Username": {
"Attributes": {
"Required": false,
"Type": "String"
}
}
}
},
"Delete identity": {
"Admin rights required": true,
"Endpoint": "/api/identity/delete/<identity_id>"
},
"Edit identity": {
"Admin rights required": true,
"Endpoint": "/api/identity/edit/<identity_id>",
"Fields": {
"Email": {
"Attributes": {
"Required": true,
"Type": "String"
}
},
"First": {
"Attributes": {
"Required": true,
"Type": "String"
}
},
"Middle": {
"Attributes": {
"Required": false,
"Type": "String"
}
},
"Phone": {
"Attributes": {
"Required": true,
"Type": "String"
}
},
"Surname": {
"Attributes": {
"Required": true,
"Type": "String"
}
},
"Username": {
"Attributes": {
"Required": false,
"Type": "String"
}
}
}
}
},
"Retrieve identity data": {
"Admin rights required": true,
"Endpoint": "/api/identities",
"Optional Search Filters": {
"Email": "String",
"Firstname": "String",
"Fullname": "String",
"Identity ID": "Integer",
"Middlename": "String",
"Phone": "String",
"Surname": "String",
"Username": "String"
}
}
}
},
"Results": {
"GET": {
"Retrieve account data": {
"Admin rights required": false,
"Endpoint": "/api/results",
"Optional Search Filters": {
"Associated Task ID": "Integer",
"Created At": "String - Timestamp",
"Domain": "String",
"ID": "Integer",
"Link": "String",
"Output Files": "String",
"Plugin": "String",
"Result Type": "String",
"Screenshot Requested": "String",
"Screenshot URL": "String",
"Status": "String",
"Title": "String",
"Updated At": "String - Timestamp"
}
}
},
"POST": {
"Close a result": {
"Admin rights required": true,
"Endpoint": "/api/result/changestatus/close/<result_id>"
},
"Create a new manual result": {
"Admin rights required": true,
"Endpoint": "/api/result/new",
"Fields": {
"Name": {
"Attributes": {
"Required": true,
"Type": "String"
}
},
"Type": {
"Attributes": {
"Required": true,
"Type": "String"
}
},
"URL": {
"Attributes": {
"Required": true,
"Type": "String"
}
}
}
},
"Delete a result": {
"Admin rights required": true,
"Endpoint": "/api/result/delete/<result_id>"
},
"Label a result as under inspection": {
"Admin rights required": true,
"Endpoint": "/api/result/changestatus/inspect/<result_id>"
},
"Label a result as under review": {
"Admin rights required": true,
"Endpoint": "/api/result/changestatus/review/<result_id>"
},
"Re-open a result": {
"Admin rights required": true,
"Endpoint": "/api/result/changestatus/open/<result_id>"
}
}
},
"Settings": {
"GET": {
"Retrieve configuration data": {
"Admin rights required": true,
"Endpoint": "/api/settings/configurations/<type_of_configuration>"
}
},
"POST": {
"Update configuration": {
"Admin rights required": true,
"Endpoint": "/api/settings/configure/<type_of_configuration>",
"Fields": {
"data": {
"Notes": "This data depends on the configuration you are updating.",
"Required": true,
"Type": "Dictionary"
},
"object": {
"Required": true,
"Type": "String"
}
}
}
}
},
"Tasks": {
"GET": {
"Retrieve account data": {
"Admin rights required": false,
"Endpoint": "/api/tasks",
"Optional Search Filters": {
"Created At": "String - Timestamp",
"Description": "String",
"Frequency": "String - Cronjob",
"ID": "Integer",
"Limit": "Integer",
"Plugin": "String",
"Query": "String",
"Status": "String",
"Updated At": "String - Timestamp"
}
},
"Shows which output options are enabled for tasks to export their results to": {
"Admin rights required": true,
"Endpoint": "/api/tasks/outputs/check"
},
"Shows which task apis are configured": {
"Admin rights required": true,
"Endpoint": "/api/tasks/inputs/check"
}
},
"POST": {
"Create a new task": {
"Admin rights required": true,
"Endpoint": "/api/task/new",
"Fields": {
"Description": {
"Required": false,
"Type": "String"
},
"Frequency": {
"Required": false,
"Type": "String - Cronjob"
},
"Limit": {
"Required": false,
"Type": "Integer"
},
"Query": {
"Required": true,
"Type": "String"
},
"Task Type": {
"Required": true,
"Type": "String"
}
}
},
"Delete a task": {
"Admin rights required": true,
"Endpoint": "/api/task/delete/<task_id>"
},
"Duplicate a task": {
"Admin rights required": true,
"Endpoint": "/api/task/duplicate/<task_id>"
},
"Edit a task": {
"Admin rights required": true,
"Endpoint": "/api/task/edit/<task_id>",
"Fields": {
"Description": {
"Required": false,
"Type": "String"
},
"Frequency": {
"Required": false,
"Type": "String - Cronjob"
},
"Limit": {
"Required": false,
"Type": "Integer"
},
"Query": {
"Required": true,
"Type": "String"
},
"Task Type": {
"Required": true,
"Type": "String"
}
}
},
"Run a task": {
"Admin rights required": true,
"Endpoint": "/api/task/run/<task_id>"
}
}
},
"User Management": {
"GET": {
"Retrieve account data": {
"Admin rights required": true,
"Endpoint": "/api/accounts",
"Optional Search Filters": {
"Administrative Rights": "Boolean",
"Blocked": "Boolean",
"ID": "Integer",
"Username": "String"
}
}
},
"POST": {
"Change any user's password": {
"Admin rights required": true,
"Endpoint": "/api/account/password/change/<account_id>",
"Fields": {
"Password": {
"Attributes": {
"Required": true,
"Type": "String"
}
},
"Password Retype": {
"Attributes": {
"Required": true,
"Type": "String"
}
}
}
},
"Create new account": {
"Admin rights required": true,
"Endpoint": "/api/account/new",
"Fields": {
"Password": {
"Attributes": {
"Required": true,
"Type": "String"
}
},
"Password Retype": {
"Attributes": {
"Required": true,
"Type": "String"
}
},
"Username": {
"Attributes": {
"Required": true,
"Type": "String"
}
}
}
},
"Delete account": {
"Admin rights required": true,
"Endpoint": "/api/account/delete/<account_id>"
},
"Disable account": {
"Admin rights required": true,
"Endpoint": "/api/account/disable/<account_id>"
},
"Enable account": {
"Admin rights required": true,
"Endpoint": "/api/account/enable/<account_id>"
},
"Give account administrative rights": {
"Admin rights required": true,
"Endpoint": "/api/account/promote/<account_id>"
},
"Strip account of administrative rights": {
"Admin rights required": true,
"Endpoint": "/api/account/demote/<account_id>"
}
}
}
}
}Security:
JWTs can easily be decoded online without the verification signature. Therefore if the information in the JWT is easily exposed this present two issues:
a. If sensitive data is stored in the JWT this can be easily stolen. i.e. Passwords
b. If nothing is added to stop enumeration, i.e. a random and unique field, fields such as user_id could be altered allowing users to enumerate other JWTs simply by changing their user_id, resulting in them being able to hijack another user's API Key.
Therefore all JWT payloads have been structured in the following way.
{
"id": 1,
"name": "admin",
"admin": true,
"time-created": "Timestamp",
"nonce": "RANDOM STRING"
}Both the timestamps and the nonce provide randomness to these tokens. Only the encoded JWT is stored in the database. The program finds the user based on the user_id in the JWT (If it can be decoded to begin with), where validation rules apply to verify the id field is an integer. Then the JWT stored in the database is retrieved and checked against the supplied JWT. Only if they match will the API permit you the content you requested. Additionally, the only information in the JWT that is trusted is the id field. The rest simply assist in creating a long and unique JWT. Lastly, the nonce is generated using the secrets python3 library which is considered to be securely random.
API expiry can be configured under the "web_app" section in the config.json file, under the "api_validity_minutes" field. Rate limiting can be controlled with the last two options. In the below case, rate-limiting will only allow 10 calls per/minute:
"web_app": {
"debug": false,
"host": "127.0.0.1",
"port": 5000,
"certificate_file": "../certs/certificate.crt",
"key_file": "../certs/privateKey.key",
"api_secret": "SECRET",
"api_validity_minutes": 60,
"api_max_calls": 10,
"api_period_in_seconds": 60
}