Starting on discord, switching to remote env

This commit is contained in:
sneakers-the-rat 2023-08-01 19:06:25 -07:00
parent 1b7715d0c8
commit e9e5e8f7ec
10 changed files with 130 additions and 34 deletions

View file

@ -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) (the ones that can use the website to join)
- [Slack](#Slack) - [Slack](#Slack)
- [Discord](#Discord)
### Slack ### 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: `<yourdomain.etc.>/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 `<yourdomain.etc>/api/discord/oauth_redirect`
## Deployment ## Deployment

View file

@ -9,11 +9,6 @@ POSTGRES_USER=
POSTGRES_PASSWORD= POSTGRES_PASSWORD=
POSTGRES_DB= POSTGRES_DB=
SLACK_CLIENT_ID=
SLACK_CLIENT_SECRET=
SLACK_SIGNING_SECRET=
SLACK_STATE_SECRET=
# Used to log in to create and manage groups # Used to log in to create and manage groups
ADMIN_TOKEN= ADMIN_TOKEN=
@ -24,3 +19,19 @@ COOKIE_KEY_2=
# Location of the matterbridge binary! # Location of the matterbridge binary!
MATTERBRIDGE_BINARY= MATTERBRIDGE_BINARY=
MATTERBRIDGE_CONFIG_DIR= MATTERBRIDGE_CONFIG_DIR=
# ---------------
## Platforms
# ---------------
# Slack -----------------
SLACK_CLIENT_ID=
SLACK_CLIENT_SECRET=
SLACK_SIGNING_SECRET=
SLACK_STATE_SECRET=
# Discord ----------------
DISCORD_TOKEN=
DISCORD_CLIENT_ID=

View file

@ -13,6 +13,10 @@ export default {
signing_secret: 'SLACK_SIGNING_SECRET', signing_secret: 'SLACK_SIGNING_SECRET',
state_secret: 'SLACK_STATE_SECRET' state_secret: 'SLACK_STATE_SECRET'
}, },
discordConfig: {
token: 'DISCORD_TOKEN',
client_id: "DISCORD_CLIENT_ID"
},
admin_token: 'ADMIN_TOKEN', admin_token: 'ADMIN_TOKEN',
cookies:{ cookies:{
key1: 'COOKIE_KEY_1', key1: 'COOKIE_KEY_1',

View file

@ -13,6 +13,7 @@ import slackRoutes from "./routes/slack.routes";
import authRoutes from "./routes/auth.routes"; import authRoutes from "./routes/auth.routes";
import bridgeRoutes from './routes/bridge.routes'; import bridgeRoutes from './routes/bridge.routes';
import channelRoutes from './routes/channel.routes'; import channelRoutes from './routes/channel.routes';
import discordRoutes from "./routes/discord.routes";
import logger from "./logging"; import logger from "./logging";
@ -39,6 +40,7 @@ AppDataSource.initialize()
app.use('/slack', slackRoutes); app.use('/slack', slackRoutes);
app.use('/bridge', bridgeRoutes); app.use('/bridge', bridgeRoutes);
app.use('/channel', channelRoutes); app.use('/channel', channelRoutes);
app.use('/discord', discordRoutes);
app.all('*', (req: Request, res: Response, next: NextFunction) => { app.all('*', (req: Request, res: Response, next: NextFunction) => {
next(new AppError(404, `Route ${req.originalUrl} not found`)); next(new AppError(404, `Route ${req.originalUrl} not found`));

View file

@ -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<discordConfigType>('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)
}

View file

@ -1,7 +1,7 @@
import config from 'config'; import config from 'config';
import {Request, Response} from 'express'; import {Request, Response} from 'express';
import {AppDataSource} from "../db/data-source"; 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 {Group} from "../entities/group.entity";
import {JoinSlackChannelInput} from "../schemas/slack.schema"; import {JoinSlackChannelInput} from "../schemas/slack.schema";
import {randomUUID} from "crypto"; import {randomUUID} from "crypto";
@ -12,7 +12,7 @@ import { slackConfigType } from "../types/config";
const { InstallProvider, LogLevel, FileInstallationStore } = require('@slack/oauth'); 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 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 groupRepository = AppDataSource.getRepository(Group)
const SLACK_COOKIE_NAME = "slack-oauth-state"; const SLACK_COOKIE_NAME = "slack-oauth-state";
@ -77,10 +77,10 @@ export const SlackCallbackHandler = async(
} }
// check if we have an entity // 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){ if (!bridge){
bridge = await bridgeRepository.create(bridge_data); bridge = await slackBridgeRepository.create(bridge_data);
await bridgeRepository.save(bridge); await slackBridgeRepository.save(bridge);
logger.debug('created bridge') logger.debug('created bridge')
} else { } else {
@ -88,7 +88,7 @@ export const SlackCallbackHandler = async(
// Don't overwrite existing label // Don't overwrite existing label
bridge_data.Label = bridge.Label bridge_data.Label = bridge.Label
bridge_data = {...bridge, ...bridge_data} bridge_data = {...bridge, ...bridge_data}
let newbridge = await bridgeRepository.save(bridge_data) let newbridge = await slackBridgeRepository.save(bridge_data)
} }
res.send('<html><body><h1>Success! Return to the chatbridge login window.</h1><h3>This tab will close in 3 seconds...</h3><script>window.setTimeout(window.close, 3000)</script></body>') res.send('<html><body><h1>Success! Return to the chatbridge login window.</h1><h3>This tab will close in 3 seconds...</h3><script>window.setTimeout(window.close, 3000)</script></body>')
@ -107,7 +107,7 @@ export const getChannelsHandler = async(
req: Request, req: Request,
res: Response 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 { try {
fetch('https://slack.com/api/conversations.list', { fetch('https://slack.com/api/conversations.list', {
@ -150,7 +150,7 @@ export const joinChannelsHandler = async(
res: Response 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', { fetch('https://slack.com/api/conversations.invite', {
method: "POST", method: "POST",
@ -184,7 +184,7 @@ export const getBotInfo = async(
req: Request, req: Request,
res: Response 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 { try {
fetch('https://slack.com/api/auth.test', { fetch('https://slack.com/api/auth.test', {

View file

@ -20,13 +20,6 @@ export class Bridge extends Model {
@Column() @Column()
Label: string; 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 // Used to fetch the bridge data from the client while installing
@Column() @Column()
state_token: string; state_token: string;
@ -37,16 +30,6 @@ export class Bridge extends Model {
}) })
Token: string; Token: string;
@Column({
nullable: true
})
user_token: string;
@Column({
nullable:true
})
bot_id: string;
@Column({ @Column({
default: true default: true
}) })
@ -58,8 +41,7 @@ export class Bridge extends Model {
}) })
RemoteNickFormat: string; RemoteNickFormat: string;
// Bridged channels (not the channels in the slack/discord/etc.)
@OneToMany(() => Channel, (channel) => channel.bridge, @OneToMany(() => Channel, (channel) => channel.bridge,
{ {
cascade: ["remove"] 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() @ChildEntity()
export class MatrixBridge extends Bridge { export class MatrixBridge extends Bridge {
// Matrix-specific // Matrix-specific

View file

@ -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

View file

@ -4,3 +4,8 @@ export interface slackConfigType {
signing_secret: string, signing_secret: string,
state_secret: string state_secret: string
} }
export interface discordConfigType {
token: string;
client_id: string;
}