-
-
Notifications
You must be signed in to change notification settings - Fork 78
The Scrummage API
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.
- /api/auth (Used to retrieve either an existing or new JSON Web Token.) 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 the request as per the following:
Authorization: Bearer YOUR.JWT.TOKEN
Full 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"
}
}
}
},
"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>"
}
}
},
"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"
}
},
"Show which output options are enabled for receiving task results": {
"Admin rights required": true,
"Endpoint": "/api/tasks/output/options/verify"
}
},
"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:
API Security is a fairly young field; however, a few measures have been implemented by design.
JWTs can easily be decoded online without the verification signature (Or API Secret used in the config.json file). 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 enumerated allowing end-users to enumerate other JWTs simply by changing their user_id.
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
},