- Notifications
You must be signed in to change notification settings - Fork2
Tourist is an HTTP API around Microsoft Playwright for CTF challenges
License
CTFd/tourist
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Simply put - Tourist is an agent that will visit web applications and perform given actions.It was designed for use with CTF challenges that require visiting by a real browser to trigger vulnerabilities.
Instead of packaging a headless browser inside all of your challenges via puppeteer/playwright/selenium - you candeploy a single instance of Tourist somewhere and have all your challenges talk with it to schedule visits.
It can also perform additional actions, for example if your challenge requires generating PDF files from HTMLyou can also outsource this task to Tourist.
First you need to deploy Tourist.
- We recommend using our docker image from
ghcr.io/ctfd/tourist
- You can also reference the
docker-compose.yml
file
- We recommend using our docker image from
With authentication enabled, you need to copy the issuer token generated for you during the application start up.
Next, using that token, you need to create a token for your application to schedule jobs:
# Issue a non-strict, visit token for visiting example.com valid for 7 days.importrequestsurl="http://localhost:3000/api/v1/issue-token"token="<issuer-token>"headers= {"Authorization":f"Bearer{token}"}data= {"scope":"https://example.com",}response=requests.post(url,json=data,headers=headers)print(response.json()["token"])
In response to that request, you will receive a visit token (by default valid for 7 days), which you can use toschedule jobs:
# Go to https://example.com and take a screenshot synchronouslyimportbase64importrequestsurl="http://localhost:3000/api/v1/sync-job"token="<visit-token>"headers= {"Authorization":f"Bearer{token}"}data= {"steps": [ {"url":"https://example.com"} ],# You can create a video and a pdf the same way by using additional options: "RECORD" and "PDF""options": ["SCREENSHOT"]}response=requests.post(url,json=data,headers=headers).json()ifresponse["status"]=="success":screenshot_b64=response["result"]["screenshot"]screenshot=base64.b64decode(screenshot_b64)withopen("screenshot.png","wb+")asscreenshot_file:screenshot_file.write(screenshot)
For additional guidance, be sure to check:
- Thedocs
- Theexamples directory
- OpenAPI docs (by navigating to a deployed Tourist endpoint)
- Unit tests:
runner.test.ts
,async-job.test.ts
andsync-job.test.ts
We recommend using Tourist in Docker, and configuring it with environmental variables. Example (default) config can beseen in the.env.example
file which is self-explanatory.
The only required setting is theREDIS_URL
. It's also recommend to provide a securely randomSECRET
- Tourist willgenerate a random secret key on startup, however if you happen to restart the application your old tokens will becomeinvalid.
For full reference please check our guide oninstalling Tourist
Token authentication is enabled by default. It can be disabled with environmental variables.
Tourist expects theAuthorization
header with a value ofBearer <token>
.
For full reference please check our guide onTourist authentication
You can specify actions to be performed during each step. Actions are an array of strings (code) to be passed toplaywright inside an isolated sandbox. There are a few guidelines for you to follow:
- You will want to execute methods off of the provided
page
, andcontext
variables - which will be a playwrightPage
, andBrowserContext
objects respectively - already afternavigation to the specified url.- You can register event handlers by using
page.on()
-which will be registered before the page loads. - Use camelCased methods - as in the playwright docs.
- Use JavaScript syntax - TypeScript will not be precompiled.
- Do not use
screenshot
/record
in actions - instead specify this in Tourist options when dispatching the request.
- You can register event handlers by using
- Treat actions as top-level synchronous code. They may return either a concrete value, or a Promise - which will beawaited, however it's not an async context, so if you need to use
async
/await
wrap your action in anIIFE expression.- As actions can return a Promise - it's completely fine to execute simple playwright calls which return a Promise,without the added complexity - for example
page.click('a')
is a valid action (althoughdepreciated, which will be awaited. - Multi-line statements are allowed inside an IIFE expression, so follow the same pattern if you need to use forexample, a for loop.
- As actions can return a Promise - it's completely fine to execute simple playwright calls which return a Promise,without the added complexity - for example
For full reference please check our guide onTourist actions.
We have been using a previous version of Tourist internally at CTFd for some time. The legacy API matches our previoussimpler specification - most notably itdoes not support authentication, and does not allow choosing betweensynchronous and asynchronous jobs. It's provided as a compatibility layer for us and should be considered deprecated.
Tourist can capture exceptions to Sentry by configuring theSENTRY_DSN
environment variable.
About
Tourist is an HTTP API around Microsoft Playwright for CTF challenges