diff --git a/config/custom-environment-variables.ts b/config/custom-environment-variables.ts index 53abdd3..13c0a50 100755 --- a/config/custom-environment-variables.ts +++ b/config/custom-environment-variables.ts @@ -7,5 +7,10 @@ export default { password: 'POSTGRES_PASSWORD', database: 'POSTGRES_DB', }, + slackConfig: { + client_id: 'SLACK_CLIENT_ID', + client_secret: 'SLACK_CLIENT_SECRET', + signing_secret: 'SLACK_SIGNING_SECRET' + }, admin_token: 'ADMIN_TOKEN' } \ No newline at end of file diff --git a/example.env b/example.env index 1382ac0..350e1e7 100644 --- a/example.env +++ b/example.env @@ -7,4 +7,8 @@ POSTGRES_USER= POSTGRES_PASSWORD= POSTGRES_DB= +SLACK_CLIENT_ID= +SLACK_CLIENT_SECRET= +SLACK_SIGNING_SECRET= + ADMIN_TOKEN= \ No newline at end of file diff --git a/server/app.ts b/server/app.ts index 063d811..727a282 100644 --- a/server/app.ts +++ b/server/app.ts @@ -8,6 +8,7 @@ import { AppDataSource } from './db/data-source'; import AppError from './errors/appError'; import groupRoutes from "./routes/group.routes"; +import slackRoutes from "./routes/slack.routes"; @@ -25,6 +26,13 @@ AppDataSource.initialize() app.use('/groups', groupRoutes); + // app.use('/slack', async (req:Request, res:Response) => { + // console.log(req) + // let code = req.query.code; + // }); + + app.use('/slack', slackRoutes); + app.all('*', (req: Request, res: Response, next: NextFunction) => { next(new AppError(404, `Route ${req.originalUrl} not found`)); }); diff --git a/server/controllers/slack.controller.ts b/server/controllers/slack.controller.ts new file mode 100644 index 0000000..9110384 --- /dev/null +++ b/server/controllers/slack.controller.ts @@ -0,0 +1,74 @@ +import config from 'config'; +const { InstallProvider, LogLevel, FileInstallationStore } = require('@slack/oauth'); +import {NextFunction, Request, Response} from 'express'; +import {AppDataSource} from "../db/data-source"; +import {Bridge} from "../entities/bridge.entity"; +import {Group} from "../entities/group.entity"; +import { randomUUID } from "crypto"; + +const scopes = ['bot', 'channels:write', 'chat:write:bot', 'chat:write:user', 'users.profile:read']; +const bridgeRepository = AppDataSource.getRepository(Bridge) +const groupRepository = AppDataSource.getRepository(Group) + + +const slackConfig = config.get<{ + client_id: string, + client_secret: string, + signing_secret: string +}>('slackConfig'); + +const installer = new InstallProvider({ + clientId: slackConfig.client_id, + clientSecret: slackConfig.client_secret, + authVersion: 'v1', + scopes, + stateSecret: randomUUID(), + installationStore: new FileInstallationStore(), + logLevel: LogLevel.DEBUG, + +}) + +export const SlackInstallHandler = async( + req: Request, + res: Response +) => { + + + await installer.handleInstallPath(req, res, {}, { + scopes, + metadata: {'name':'my-slack-name','group':'MyGroup'} + }); +} + + +export const SlackCallbackHandler = async( + req: Request, + res: Response +) => { + // using custom success and failure handlers + const callbackOptions = { + success: async (installation, installOptions, req, res) => { + console.log(installation, installOptions, req.body, req.content, req.query, req.params) + console.log(installation.team.id, installation.team.name, installation.bot.token); + let bridge = await bridgeRepository.create({ + 'Protocol': 'slack', + 'Label': installation.metadata.name, + 'team_id': installation.team.id, + 'team_name': installation.team.name, + 'Token': installation.bot.token + }); + let result = await bridgeRepository.save(bridge); + + + res.send(result); + + }, + failure: (error, installOptions , req, res) => { + res.send('failure'); + }, + } + + + await installer.handleCallback(req, res, callbackOptions); + +} \ No newline at end of file diff --git a/server/entities/bridge.entity.ts b/server/entities/bridge.entity.ts index 8ce1abf..08f14f0 100644 --- a/server/entities/bridge.entity.ts +++ b/server/entities/bridge.entity.ts @@ -20,6 +20,18 @@ 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; + + @Column({ + unique: true + }) + Token: string; + @Column({ default: true }) @@ -31,10 +43,7 @@ export class Bridge extends Model { }) RemoteNickFormat: string; - @Column({ - unique: true - }) - Token: string; + @OneToMany(() => Channel, (channel) => channel.bridge) channels: Channel[] diff --git a/server/routes/slack.routes.ts b/server/routes/slack.routes.ts new file mode 100644 index 0000000..a830ece --- /dev/null +++ b/server/routes/slack.routes.ts @@ -0,0 +1,16 @@ +import express from 'express'; + +import { + SlackInstallHandler, + SlackCallbackHandler +} from '../controllers/slack.controller' + +const router = express.Router(); + +router.route('/install') + .get(SlackInstallHandler) + +router.route('/oauth_redirect') + .get(SlackCallbackHandler) + +export default router \ No newline at end of file diff --git a/server/services/groupConfig.service.ts b/server/services/groupConfig.service.ts new file mode 100644 index 0000000..a4a6776 --- /dev/null +++ b/server/services/groupConfig.service.ts @@ -0,0 +1,11 @@ +/* +Regenerate the group .toml configuration file +*/ + +import {Group} from "../entities/group.entity"; +import {AppDataSource} from "../db/data-source"; + + +export const updateGroup = async(name:string){ + +} \ No newline at end of file