From e9e5e8f7eccd97cf28479fc8a89b9384531b1ac2 Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Tue, 1 Aug 2023 19:06:25 -0700 Subject: [PATCH] Starting on discord, switching to remote env --- README.md | 10 +++- .../src/components/platforms/discordLogin.tsx | 0 example.env | 21 ++++++-- server/config/custom-environment-variables.ts | 4 ++ server/src/app.ts | 2 + server/src/controllers/discord.controller.ts | 32 ++++++++++++ server/src/controllers/slack.controller.ts | 18 +++---- server/src/entities/bridge.entity.ts | 52 ++++++++++++------- server/src/routes/discord.routes.ts | 20 +++++++ server/src/types/config.ts | 5 ++ 10 files changed, 130 insertions(+), 34 deletions(-) create mode 100644 client/src/components/platforms/discordLogin.tsx create mode 100644 server/src/controllers/discord.controller.ts create mode 100644 server/src/routes/discord.routes.ts diff --git a/README.md b/README.md index ce0cf0e..6276b45 100644 --- a/README.md +++ b/README.md @@ -20,11 +20,19 @@ Very unfinished!! Mostly a programming exercise for me for now to practice fulls (the ones that can use the website to join) - [Slack](#Slack) +- [Discord](#Discord) ### Slack -https://github.com/slackapi/node-slack-sdk +- Set up Slack App with old style bot according to matterbridge instructions: https://github.com/42wim/matterbridge/wiki/Slack-bot-setup +- Configure slack app to use the callback API url: `/api/slack/oauth_redirect` +- Set your `.env` variables! +### Discord + +- Set up Discord App according to matterbridge instructions: https://github.com/42wim/matterbridge/wiki/Discord-bot-setup +- Additionally enable "[Requires OAUTH2 Code Grant](https://discord.com/developers/docs/topics/oauth2#advanced-bot-authorization)" in your bot's authorization flow settings +- Set the redirect URL to `/api/discord/oauth_redirect` ## Deployment diff --git a/client/src/components/platforms/discordLogin.tsx b/client/src/components/platforms/discordLogin.tsx new file mode 100644 index 0000000..e69de29 diff --git a/example.env b/example.env index 8c04370..8824b0e 100644 --- a/example.env +++ b/example.env @@ -9,11 +9,6 @@ POSTGRES_USER= POSTGRES_PASSWORD= POSTGRES_DB= -SLACK_CLIENT_ID= -SLACK_CLIENT_SECRET= -SLACK_SIGNING_SECRET= -SLACK_STATE_SECRET= - # Used to log in to create and manage groups ADMIN_TOKEN= @@ -24,3 +19,19 @@ COOKIE_KEY_2= # Location of the matterbridge binary! MATTERBRIDGE_BINARY= MATTERBRIDGE_CONFIG_DIR= + +# --------------- +## Platforms +# --------------- + +# Slack ----------------- +SLACK_CLIENT_ID= +SLACK_CLIENT_SECRET= +SLACK_SIGNING_SECRET= +SLACK_STATE_SECRET= + +# Discord ---------------- +DISCORD_TOKEN= +DISCORD_CLIENT_ID= + + diff --git a/server/config/custom-environment-variables.ts b/server/config/custom-environment-variables.ts index 8d9efd2..0d325ee 100755 --- a/server/config/custom-environment-variables.ts +++ b/server/config/custom-environment-variables.ts @@ -13,6 +13,10 @@ export default { signing_secret: 'SLACK_SIGNING_SECRET', state_secret: 'SLACK_STATE_SECRET' }, + discordConfig: { + token: 'DISCORD_TOKEN', + client_id: "DISCORD_CLIENT_ID" + }, admin_token: 'ADMIN_TOKEN', cookies:{ key1: 'COOKIE_KEY_1', diff --git a/server/src/app.ts b/server/src/app.ts index 3e5a4d4..8020e9b 100644 --- a/server/src/app.ts +++ b/server/src/app.ts @@ -13,6 +13,7 @@ import slackRoutes from "./routes/slack.routes"; import authRoutes from "./routes/auth.routes"; import bridgeRoutes from './routes/bridge.routes'; import channelRoutes from './routes/channel.routes'; +import discordRoutes from "./routes/discord.routes"; import logger from "./logging"; @@ -39,6 +40,7 @@ AppDataSource.initialize() app.use('/slack', slackRoutes); app.use('/bridge', bridgeRoutes); app.use('/channel', channelRoutes); + app.use('/discord', discordRoutes); app.all('*', (req: Request, res: Response, next: NextFunction) => { next(new AppError(404, `Route ${req.originalUrl} not found`)); diff --git a/server/src/controllers/discord.controller.ts b/server/src/controllers/discord.controller.ts new file mode 100644 index 0000000..dcaf0f4 --- /dev/null +++ b/server/src/controllers/discord.controller.ts @@ -0,0 +1,32 @@ + +import {Request, Response} from "express"; +import {randomUUID} from "crypto"; +import config from "config"; +import {discordConfigType} from "../types/config"; +import {DiscordBridge} from "../entities/bridge.entity"; +import {AppDataSource} from "../db/data-source"; + + + +const discordBridgeRepository = AppDataSource.getRepository(DiscordBridge) +const discordConfig = config.get('discordConfig'); + +export const DiscordInstallLinkHandler = async( + req: Request, + res: Response +) => { + let state_token = randomUUID() + req.session.state_token = state_token; + + const url = `https://discordapp.com/oauth2/authorize?&client_id=${discordConfig.client_id}&scope=bot&permissions=536870912&state=${state_token}` + + +} + + +export const DiscordOAuthHandler = async( + req: Request, + res: Response +) => { + console.log('discord oauth', req.body, req.query) +} diff --git a/server/src/controllers/slack.controller.ts b/server/src/controllers/slack.controller.ts index 7558622..0534258 100644 --- a/server/src/controllers/slack.controller.ts +++ b/server/src/controllers/slack.controller.ts @@ -1,7 +1,7 @@ import config from 'config'; import {Request, Response} from 'express'; import {AppDataSource} from "../db/data-source"; -import {Bridge} from "../entities/bridge.entity"; +import {Bridge, SlackBridge} from "../entities/bridge.entity"; import {Group} from "../entities/group.entity"; import {JoinSlackChannelInput} from "../schemas/slack.schema"; import {randomUUID} from "crypto"; @@ -12,7 +12,7 @@ import { slackConfigType } from "../types/config"; const { InstallProvider, LogLevel, FileInstallationStore } = require('@slack/oauth'); const scopes = ['bot', 'channels:write', 'channels:write.invites', 'chat:write:bot', 'chat:write:user', 'users.profile:read']; -const bridgeRepository = AppDataSource.getRepository(Bridge) +const slackBridgeRepository = AppDataSource.getRepository(SlackBridge) const groupRepository = AppDataSource.getRepository(Group) const SLACK_COOKIE_NAME = "slack-oauth-state"; @@ -77,10 +77,10 @@ export const SlackCallbackHandler = async( } // check if we have an entity - let bridge = await bridgeRepository.findOneBy({Token: installation.bot.token}) + let bridge = await slackBridgeRepository.findOneBy({Token: installation.bot.token}) if (!bridge){ - bridge = await bridgeRepository.create(bridge_data); - await bridgeRepository.save(bridge); + bridge = await slackBridgeRepository.create(bridge_data); + await slackBridgeRepository.save(bridge); logger.debug('created bridge') } else { @@ -88,7 +88,7 @@ export const SlackCallbackHandler = async( // Don't overwrite existing label bridge_data.Label = bridge.Label bridge_data = {...bridge, ...bridge_data} - let newbridge = await bridgeRepository.save(bridge_data) + let newbridge = await slackBridgeRepository.save(bridge_data) } res.send('

Success! Return to the chatbridge login window.

This tab will close in 3 seconds...

') @@ -107,7 +107,7 @@ export const getChannelsHandler = async( req: Request, res: Response ) => { - let bridge = await bridgeRepository.findOneBy({state_token: req.session.state_token}) + let bridge = await slackBridgeRepository.findOneBy({state_token: req.session.state_token}) try { fetch('https://slack.com/api/conversations.list', { @@ -150,7 +150,7 @@ export const joinChannelsHandler = async( res: Response ) => { - let bridge = await bridgeRepository.findOneBy({state_token: req.session.state_token}) + let bridge = await slackBridgeRepository.findOneBy({state_token: req.session.state_token}) fetch('https://slack.com/api/conversations.invite', { method: "POST", @@ -184,7 +184,7 @@ export const getBotInfo = async( req: Request, res: Response ) => { - let bridge = await bridgeRepository.findOneBy({state_token: req.session.state_token}) + let bridge = await slackBridgeRepository.findOneBy({state_token: req.session.state_token}) try { fetch('https://slack.com/api/auth.test', { diff --git a/server/src/entities/bridge.entity.ts b/server/src/entities/bridge.entity.ts index 144bc1c..aa53f79 100644 --- a/server/src/entities/bridge.entity.ts +++ b/server/src/entities/bridge.entity.ts @@ -20,13 +20,6 @@ export class Bridge extends Model { @Column() Label: string; - // The ID of the team - @Column({nullable:true}) - team_id: string; - - @Column({nullable:true}) - team_name: string; - // Used to fetch the bridge data from the client while installing @Column() state_token: string; @@ -37,16 +30,6 @@ export class Bridge extends Model { }) Token: string; - @Column({ - nullable: true - }) - user_token: string; - - @Column({ - nullable:true - }) - bot_id: string; - @Column({ default: true }) @@ -58,8 +41,7 @@ export class Bridge extends Model { }) RemoteNickFormat: string; - - + // Bridged channels (not the channels in the slack/discord/etc.) @OneToMany(() => Channel, (channel) => channel.bridge, { cascade: ["remove"] @@ -68,6 +50,38 @@ export class Bridge extends Model { } +@ChildEntity() +export class SlackBridge extends Bridge { + // The ID of the team + @Column({nullable:true}) + team_id: string; + + @Column({nullable:true}) + team_name: string; + + @Column({ + nullable: true + }) + user_token: string; + + @Column({ + nullable:true + }) + bot_id: string; + +} + +@ChildEntity() +export class DiscordBridge extends Bridge { + // Server name - needed to use multiple 'servers' with a single discord app + @Column() + Server: string; + + // Analogous to team_id in slack bridge + @Column() + guild_id: string; +} + @ChildEntity() export class MatrixBridge extends Bridge { // Matrix-specific diff --git a/server/src/routes/discord.routes.ts b/server/src/routes/discord.routes.ts new file mode 100644 index 0000000..f9aa45e --- /dev/null +++ b/server/src/routes/discord.routes.ts @@ -0,0 +1,20 @@ +import express from 'express'; + +import { + DiscordInstallLinkHandler, + DiscordOAuthHandler +} from "../controllers/discord.controller"; + +import { + requireStateToken +} from "../middleware/cookies"; + +const router = express.Router(); +router.route('/install') + .get(DiscordInstallLinkHandler) + +router.route('/oauth_redirect') + .get(DiscordOAuthHandler) + + +export default router diff --git a/server/src/types/config.ts b/server/src/types/config.ts index 02545b9..3779f08 100644 --- a/server/src/types/config.ts +++ b/server/src/types/config.ts @@ -4,3 +4,8 @@ export interface slackConfigType { signing_secret: string, state_secret: string } + +export interface discordConfigType { + token: string; + client_id: string; +}