Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@
# the Discord command, set the ID of the role below, else leave this field empty.
#DISCORD_REGISTRATION_ROLE_ID=discord_id

# Mattermost Integration
# USE_MATTERMOST=false
# MATTERMOST_URL=https://your-mattermost-server.com
# MATTERMOST_USERNAME=ctfnote-bot
# MATTERMOST_PASSWORD=your-bot-password
# MATTERMOST_TEAM_NAME=your-team-name
# MATTERMOST_CREATE_VOICE_CHANNELS=false
# MATTERMOST_VOICE_CHANNELS_COUNT=2
# MATTERMOST_TEAM_ALLOW_OPEN_INVITE=true

# Configure timezone and locale
# TZ=Europe/Paris
# LC_ALL=en_US.UTF-8
Expand Down
49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,55 @@ The `/create`, `/archive` and `/delete` commands are only accessible when you ha
The bot will automatically create more categories when you hit the 50 Discord channel limit, so you can have an almost infinite amount of tasks per CTF.
It is your own responsibility to stay below the Discord server channel limit, which is 500 at the moment of writing (categories count as channels).

### Add Mattermost support

CTFNote can integrate with Mattermost to automatically create a team for a created CTF and channels for tasks.

#### What it does

When enabled, CTFNote will:
- Automatically create a team and channels for each CTF
- Create task-specific channels within the CTF team

#### Setup

To enable Mattermost integration, configure the following values in your `.env` file:

```
USE_MATTERMOST=true
MATTERMOST_URL=http://your-mattermost-server:8065
MATTERMOST_USERNAME=bot-username
MATTERMOST_PASSWORD=bot-password
MATTERMOST_TEAM_ALLOW_OPEN_INVITE=true
```

#### Testing with Mattermost Preview

You can quickly test the Mattermost integration using the official preview Docker image:

```shell
docker run --name mattermost-preview -d --publish 8065:8065 mattermost/mattermost-preview:10.9.5
```

This will start a Mattermost server on `http://localhost:8065`.
The first user created will be an admin user.

After logging in:
1. Create a team or use the default one
2. Create a bot account for CTFNote (or use the admin account for testing)
3. Update your `.env` file with the appropriate values
4. Restart CTFNote to enable the integration

#### Configuration Options

- `MATTERMOST_TEAM_ALLOW_OPEN_INVITE`: When set to `true` (default), created teams will allow any user with an account on the server to join. Set to `false` if you want teams to be invite-only.

#### Requirements

- The Mattermost bot account needs permissions to create and manage teams and channels
- The bot user must belong to at least one team in Mattermost
- The Mattermost server must be accessible from the CTFNote API container

### Migration

If you already have an instance of CTFNote in a previous version and wish to
Expand Down
8 changes: 8 additions & 0 deletions api/.env.dev
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,12 @@ DISCORD_BOT_TOKEN=secret_token
DISCORD_SERVER_ID=server_id
DISCORD_VOICE_CHANNELS=3

USE_MATTERMOST=false
MATTERMOST_URL=http://localhost:8065
MATTERMOST_USERNAME=username
MATTERMOST_PASSWORD=password
MATTERMOST_CREATE_VOICE_CHANNELS=true
MATTERMOST_VOICE_CHANNELS_COUNT=2
MATTERMOST_TEAM_ALLOW_OPEN_INVITE=true

WEB_PORT=3000
Binary file not shown.
Binary file not shown.
Binary file added api/.yarn/cache/fsevents-patch-19706e7e35-10.zip
Binary file not shown.
2 changes: 2 additions & 0 deletions api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
"@graphile-contrib/pg-simplify-inflector": "^6.1.0",
"@graphile/operation-hooks": "^1.0.0",
"@graphile/pg-pubsub": "4.13.0",
"@mattermost/client": "^10.9.0",
"@mattermost/types": "^10.9.0",
"axios": "^1.7.7",
"discord.js": "^14.21.0",
"dotenv": "^16.4.5",
Expand Down
24 changes: 24 additions & 0 deletions api/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ export type CTFNoteConfig = DeepReadOnly<{
registrationRoleId: string;
channelHandleStyle: DiscordChannelHandleStyle;
};
mattermost: {
enabled: boolean;
url: string;
username: string;
password: string;
teamName: string;
createVoiceChannels: boolean;
voiceChannelsCount: number;
teamAllowOpenInvite: boolean;
};
}>;

function getEnv(
Expand Down Expand Up @@ -112,6 +122,20 @@ const config: CTFNoteConfig = {
"agile"
) as DiscordChannelHandleStyle,
},
mattermost: {
enabled: getEnv("USE_MATTERMOST", "false") === "true",
url: getEnv("MATTERMOST_URL", ""),
username: getEnv("MATTERMOST_USERNAME", ""),
password: getEnv("MATTERMOST_PASSWORD", ""),
teamName: getEnv("MATTERMOST_TEAM_NAME", ""),
createVoiceChannels:
getEnv("MATTERMOST_CREATE_VOICE_CHANNELS", "false") === "true",
voiceChannelsCount: parseInt(
getEnv("MATTERMOST_VOICE_CHANNELS_COUNT", "2")
),
teamAllowOpenInvite:
getEnv("MATTERMOST_TEAM_ALLOW_OPEN_INVITE", "true") === "true",
},
};

export default config;
2 changes: 2 additions & 0 deletions api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import ConnectionFilterPlugin from "postgraphile-plugin-connection-filter";
import OperationHook from "@graphile/operation-hooks";
import discordHooks from "./discord/hooks";
import { initDiscordBot } from "./discord";
import mattermostHooks from "./mattermost/postgraphileHooks";
import PgManyToManyPlugin from "@graphile-contrib/pg-many-to-many";
import ProfileSubscriptionPlugin from "./plugins/ProfileSubscriptionPlugin";

Expand Down Expand Up @@ -61,6 +62,7 @@ function createOptions() {
createTasKPlugin,
ConnectionFilterPlugin,
discordHooks,
mattermostHooks,
PgManyToManyPlugin,
ProfileSubscriptionPlugin,
],
Expand Down
Loading