Deploying Seven (a Hack The Box Discord Bot for Teams)
Seven is an ambitious semi-intelligent Discord bot whose primary function is to make your Hack The Box (HTB) team’s experience easier. You can read more about the project (and see pretty screenshots) in this story. This article is about getting started deploying a self-hosted instance of Seven for your own team.
Overview
Architecture
Seven is at her core a Node.js app backed by a PostgreSQL database. When Seven gets a message, she sends it to Google’s DialogFlow service to extract an intent (what the user wants) and entities (the stuff the user is asking about, e.g. machines, team members) from natural language requests. And, of course, to allow your bot to send and receive messages in a Discord Guild, you’ll need to create a bot project within your Discord account’s Developer Portal.
Accounts
To deploy Seven, you’ll need to connect the mentioned architectural components together, which means setting up some accounts and a development environment.
- A Hack The Box account (your API access will be used for queries)
- A Discord account (your bot will be linked to this)
- A Google DialogFlow account (to ‘understand’ user questions)
- A Heroku account or other hosting option, for serving the app and DB
Don’t be scared — all parts are free and I’ll walk you through the process in less than half an hour with this article.
Step 1 — Prepare Bot Environment
You’ll need a Node.js runtime environment (tested on v14) and PostgreSQL database to get Seven up and listening for Discord messages. I recommend Heroku for this as it’s simple and has all the required functionality for free (as of late 2021). I’ll explain here the process for both Heroku and self-hosted environments.
Heroku, I choose you:
1: Sign up for a Free account on Heroku, if you don’t have one already.
2: Deploy your own instance of Seven on Heroku in one click from the official Seven repo: Deploy Seven to Heroku. You’ll be asked to provide several ‘Config Vars’ (environment variables) — don’t click “Deploy app” yet; you will collect these in the next few steps. Leave the page open for now.
I want to host Seven myself:
You can host Seven yourself from a Windows or Linux system (macOS not tested, but may work just fine). If you’re using your own server, the process will take a few more steps. You’ll need a Node.js runtime installed (see https://nodejs.org/en/ for instructions for your platform), and should setup a local PostgreSQL server as well (see https://www.postgresql.org/download/) if you don’t plan to use a remote database service.
You will need to create:
- an empty database;
- a database user account with privileges on the previous database.
You can then construct a database link for Seven to use, in the format: postgres://db_uname:db_user_pass@host_ip/db_name
(example: postgres://seven_node:5bb0023aa96a32f862@localhost/seven_local
. (This will be passed later as an environment variable (“DATABASE_URL
”) to the Node app)
To setup the Seven bot / listener /server, clone the Seven repository to some directory:git clone https://github.com/Propolisa/Seven
Next, from within the Seven directory, run npm install
and wait for dependency packages to be installed. Create an empty .env
file in the config
directory, e.g. config/.env
. This is where you will store sensitive token information for the bot to operate.
Step 2 — Discord Developer Portal
You’ll need to create a bot project with Discord so your Seven instance can actually send and receive messages on the platform. You’ll also need to collect a few channel, guild and user IDs so your bot knows where to talk and listen (and who to respect!).
Create a Discord Bot
- Login to Discord in a browser
- Access the Developer Portal
- Click New Application — Name it “Seven” or whatever you like
- Using the left-hand menu, navigate to the Bot section. Click Add Bot on the new page.
- Personalize your bot here as desired (although currently, it will only respond to the name ‘seven’ in channels)
- Uncheck “Public Bot”. (Your Seven instance should only be used on one Discord server).
- Click “Copy” under the bot’s name field to copy the API access token for your Seven instance to connect with.
- Paste this token string in the
BOT_TOKEN
environment variable.
Collect Relevant Discord IDs:
- In the Discord client (web or desktop), navigate to User Settings (cog/gear in lower left) and choose Appearance tab, then enable Developer Mode near the bottom. This will let you copy entity IDs throughout the Discord client.
- Right-click your HTB team’s server/guild badge in the Discord client and click Copy ID. Paste this as the
DISCORD_GUILD_ID
environment variable in your Node.JS environment (if using Heroku add to Config Vars; if self-hosted add to theconfig/.env
file). - Right-click your own user badge / avatar anywhere in the Discord client and click Copy ID. Paste this as the
ADMIN_DISCORD_ID
environment variable. - If your guild has no existing custom emojis and you’re okay with Seven storing UI emoji there (e.g. OS stickers, difficulty ratings, target type images), set the
EMOJI_GUILD_ID
environment variable to the same value asDISCORD_GUILD_ID
. Otherwise, create a new server/ Guild for this purpose (call it anything, for example “Seven-Emoji”), and setEMOJI_GUILD_ID
to this new Guild ID. - Recommended: Create a bot channel on the server and copy its ID in the same way. Paste this as the
DISCORD_ANNOUNCE_CHAN_ID
environment variable. This will be a channel Seven can announce on, including member owns and other interesting stuff. (It’s nice to make a dedicated channel, so users can mute these notifications)
Step 3 — Dialogflow
Create a DialogFlow project by visiting the console here and clicking “Create Agent” and following the prompts. Give the project a name, and leave “Google Project” to the default (Google will create a new GCP project for you).
Click the Settings cog and note your Google Project id (something like mysevenproject-kilm
). Assign this to the GOOGLE_CLOUD_PROJECT
environment variable in your config/.env
or Heroku deployment.
We’re going to create a service account now for your Seven instance to talk to DialogFlow via the API.
Open the following link: https://console.cloud.google.com/apis/api/dialogflow.googleapis.com/overview
This should auto-populate your newly generated GCP project (e.g. mysevenproject-kilm
in the upper left corner, just choose it from the list if not). Click “Create Credentials” in the upper right. Choose “Dialogflow API” under “Select an API”, and select “Application data” under “What data will you be accessing?”. Select “No” for the question about whether you’ll be using other GCP services with these credentials (unless you are). Give the service account a name, (e.g. seven-dflow-access
) and an optional description. Under “Grant this service account access to project” use the filter box to choose “Dialogflow API Admin”.
Finally, click “Done”.
You’ll be taken to the Credentials view. You should now see the service account you just created under the “Service Accounts” view. Click its email identifier to open the IAM & Admin view. Go to the Keys tab, click “Add Key” and choose the JSON type, then save the generated credentials file.
Nice work so far! You’ve created a DialogFlow project and a user + credential pair for Seven to interact with the service. That means one more environment variable to set — copy the FULL CONTENTS of this file, (minus newlines) into an environment variable in your config/.env
file or Heroku deployment as GOOGLE_APPLICATION_CREDENTIALS
. This will look hideously long, like GOOGLE_APPLICATION_CREDENTIALS={“type”: “service_account”,”project_id”: “seven-huqece”,”private_key_id”: “6f3eb8d4773bsdff3adcca2e7ec6618c7df”,”private_key”: “ — — -BEGIN PRIVATE KEY — -…
Don’t worry, it’s still a healthy .env
.
Step 4 — HTB authentication
There are actually 3 ways to authenticate to HTB, and you’ll need all of them for the present:
- V3 (Legacy) API token. To get this you have to re-open the legacy interface (might have to click on a link somewhere in the profile to get to the old interface). (Yes, this might break at any time when the legacy interface gets discontinued. If / when that happens, please let me know!)
- Username (email) and password. Either use a throwaway account or, obviously, first set your password to something you don’t use anywhere else! 🔒
- V4 API token. This is newly added (as of mid 2022) to the profile settings page, and is under Profile Settings > App Tokens. (Make a reminder to update the token in your bot before it expires — I’ve put in a request for non-expiring tokens, will update here if that becomes available).
Q: Why do we need so many auth methods?
A: Basically, each auth method supports different things:V3 API token allows access to the old machines endpoint, which included more information (e.g. public subnet IP addresses of machines). This added context was nice and isn’t included anywhere in the new API responses, so machine data is still gathered from there for legacy purposes.
Username and password are used to do a proper CSRF login to the HTB app. This is needed to get CSRF for authenticating to the old site’s Pusher subscription (realtime stream of HTB events) and for getting unreleased machines (not yet available on new site).
V4 API token allows to do the heavy lifting from the new API (listing machines, users, team stats, etc) and gets around a problem of needing to refresh authentication regularly for the data refresh (for which rate limits got super annoying).
Once you have all of those ready, add them as environment variables like so:
HTB_TOKEN=YOUR_LEGACY_API_TOKENHTB_V4_TOKEN=eyJ0eXAiOiJKV1QiLCJhbG.......HTB_EMAIL=your_htb_email@any.comHTB_PASS=your_htb_password
Step 5 — Double check the env file / variables
You should now have a mighty .env
file (or Heroku variables section) configured. Verify that all of this stuff is set (except DATABASE_URL
if using Heroku Postgres addon (as in the deploy template above):
BOT_TOKEN=YOUR_DISCORD_DEVELOPER_BOT_CREDENTIALHTB_TOKEN=YOUR_LEGACY_API_TOKENHTB_V4_TOKEN=eyJ0eXAiOiJKV1QiLCJhbG.......HTB_EMAIL=your_htb_email@any.comHTB_PASS=your_htb_passwordDATABASE_URL=postgres://db_uname:db_pass@host_ip/db_name (HEROKU: THIS WILL BE HANDLED AUTOMATICALLY, DO NOT ADD)GOOGLE_APPLICATION_CREDENTIALS={YOUR_JSON_KEY}GOOGLE_CLOUD_PROJECT=your_project_tagADMIN_DISCORD_IDS=["673856718466029568"]CAPTAIN_DISCORD_IDS=["673856718466029568", "2374826378357234956"]DISCORD_GUILD_ID=744689706153109545DISCORD_ANNOUNCE_CHAN_ID=746262453642034474EMOJI_GUILD_ID=744506234553109545HTB_TEAM_ID=21024
Step 6 — Runtime!
With your massive collection of environment variables set, it’s time to run the thing. Using the Heroku template? You just need to click the deploy button.
If you followed the local setup instructions in a different hosting environment, just use node bot.js
to start Seven.
Seven will, at startup:
- Authenticate to the DialogFlow API and check if the project in the env var is valid. If it’s valid, but doesn’t have any NLP training data or ‘prior research’, it will upload a backup copy of this data stored in the codebase. This might take a few minutes to upload and train Seven’s conversational skills, be patient and feel free to check the DialogFlow console for progress! :)
- Authenticate to the PostgreSQL DB you set up (or was provisioned by Heroku). It will detect the table it uses doesn’t exist, and create it.
- Authenticate to Discord and start listening to messages in the Guild she has been added to (and which is referenced in her env variables as
DISCORD_GUILD_ID
). - Authenticate to the new and old HTB APIs for fetching team data.
- Subscribe to the HTB event stream (from the old site ‘Shoutbox’), for realtime own events and other notifications.
- Start listening for your commands! Have a look at the README to see what you can ask and do.
Well, that’s it! If all went well, your Seven instance should be running happily now. Any problems at all, ping me on Discord in the Seven Support Channel and I promise we’ll get it sorted.