From 55e145116020f53995bbb0c32ad37a68ff1e9a5a Mon Sep 17 00:00:00 2001
From: Tom Moor
Date: Tue, 29 May 2018 23:33:30 -0700
Subject: [PATCH] Slack commands and post working agagain with new flow
---
app/scenes/Settings/Slack.js | 4 +-
app/scenes/Settings/components/SlackButton.js | 6 +-
app/scenes/SlackAuth/SlackAuth.js | 80 -------------------
app/scenes/SlackAuth/index.js | 3 -
app/stores/AuthStore.js | 53 ------------
server/auth/slack.js | 37 ++++++---
6 files changed, 27 insertions(+), 156 deletions(-)
delete mode 100644 app/scenes/SlackAuth/SlackAuth.js
delete mode 100644 app/scenes/SlackAuth/index.js
diff --git a/app/scenes/Settings/Slack.js b/app/scenes/Settings/Slack.js
index 188972bdf..99a2ce114 100644
--- a/app/scenes/Settings/Slack.js
+++ b/app/scenes/Settings/Slack.js
@@ -47,7 +47,7 @@ class Slack extends React.Component {
) : (
)}
@@ -83,7 +83,7 @@ class Slack extends React.Component {
{collection.name}
diff --git a/app/scenes/Settings/components/SlackButton.js b/app/scenes/Settings/components/SlackButton.js
index 241e6ed60..6923317f1 100644
--- a/app/scenes/Settings/components/SlackButton.js
+++ b/app/scenes/Settings/components/SlackButton.js
@@ -17,11 +17,7 @@ type Props = {
function SlackButton({ auth, state, label, scopes, redirectUri }: Props) {
const handleClick = () =>
- (window.location.href = slackAuth(
- state ? auth.saveOauthState(state) : auth.genOauthState(),
- scopes,
- redirectUri
- ));
+ (window.location.href = slackAuth(state, scopes, redirectUri));
return (
} neutral>
diff --git a/app/scenes/SlackAuth/SlackAuth.js b/app/scenes/SlackAuth/SlackAuth.js
deleted file mode 100644
index dd942d88b..000000000
--- a/app/scenes/SlackAuth/SlackAuth.js
+++ /dev/null
@@ -1,80 +0,0 @@
-// @flow
-import * as React from 'react';
-import { Redirect } from 'react-router-dom';
-import type { Location } from 'react-router-dom';
-import queryString from 'query-string';
-import { observable } from 'mobx';
-import { observer, inject } from 'mobx-react';
-import { client } from 'utils/ApiClient';
-import { slackAuth } from 'shared/utils/routeHelpers';
-
-import AuthStore from 'stores/AuthStore';
-
-type Props = {
- auth: AuthStore,
- location: Location,
-};
-
-@observer
-class SlackAuth extends React.Component {
- @observable redirectTo: string;
-
- componentDidMount() {
- this.redirect();
- }
-
- async redirect() {
- const { error, code, state } = queryString.parse(
- this.props.location.search
- );
-
- if (error) {
- if (error === 'access_denied') {
- // User selected "Deny" access on Slack OAuth
- this.redirectTo = '/dashboard';
- } else {
- this.redirectTo = '/auth/error';
- }
- } else if (code) {
- if (this.props.location.pathname === '/auth/slack/commands') {
- // incoming webhooks from Slack
- try {
- await client.post('/auth.slackCommands', { code });
- this.redirectTo = '/settings/integrations/slack';
- } catch (e) {
- this.redirectTo = '/auth/error';
- }
- } else if (this.props.location.pathname === '/auth/slack/post') {
- // outgoing webhooks to Slack
- try {
- await client.post('/auth.slackPost', {
- code,
- collectionId: this.props.auth.oauthState,
- });
- this.redirectTo = '/settings/integrations/slack';
- } catch (e) {
- this.redirectTo = '/auth/error';
- }
- } else {
- // Slack authentication
- const redirectTo = sessionStorage.getItem('redirectTo');
- sessionStorage.removeItem('redirectTo');
-
- const { success } = await this.props.auth.authWithSlack(code, state);
- success
- ? (this.redirectTo = redirectTo || '/dashboard')
- : (this.redirectTo = '/auth/error');
- }
- } else {
- // signing in
- window.location.href = slackAuth(this.props.auth.genOauthState());
- }
- }
-
- render() {
- if (this.redirectTo) return ;
- return null;
- }
-}
-
-export default inject('auth')(SlackAuth);
diff --git a/app/scenes/SlackAuth/index.js b/app/scenes/SlackAuth/index.js
deleted file mode 100644
index cf1b93d0d..000000000
--- a/app/scenes/SlackAuth/index.js
+++ /dev/null
@@ -1,3 +0,0 @@
-// @flow
-import SlackAuth from './SlackAuth';
-export default SlackAuth;
diff --git a/app/stores/AuthStore.js b/app/stores/AuthStore.js
index 9cc55d230..c764e482f 100644
--- a/app/stores/AuthStore.js
+++ b/app/stores/AuthStore.js
@@ -12,7 +12,6 @@ class AuthStore {
@observable user: ?User;
@observable team: ?Team;
@observable token: ?string;
- @observable oauthState: string;
@observable isLoading: boolean = false;
@observable isSuspended: boolean = false;
@observable suspendedContactEmail: ?string;
@@ -29,7 +28,6 @@ class AuthStore {
return JSON.stringify({
user: this.user,
team: this.team,
- oauthState: this.oauthState,
});
}
@@ -63,56 +61,6 @@ class AuthStore {
window.location.href = `${BASE_URL}?done=${new Date().getTime()}`;
};
- @action
- genOauthState = () => {
- const state = Math.random()
- .toString(36)
- .substring(7);
- this.oauthState = state;
- return this.oauthState;
- };
-
- @action
- saveOauthState = (state: string) => {
- this.oauthState = state;
- return this.oauthState;
- };
-
- @action
- authWithSlack = async (code: string, state: string) => {
- // in the case of direct install from the Slack app store the state is
- // created on the server and set as a cookie
- const serverState = Cookie.get('state');
- if (state !== this.oauthState && state !== serverState) {
- return {
- success: false,
- };
- }
-
- let res;
- try {
- res = await client.post('/auth.slack', { code });
- } catch (e) {
- return {
- success: false,
- };
- }
-
- // State can only ever be used once so now's the time to remove it.
- Cookie.remove('state', { path: '/' });
-
- invariant(
- res && res.data && res.data.user && res.data.team && res.data.accessToken,
- 'All values should be available'
- );
- this.user = res.data.user;
- this.team = res.data.team;
-
- return {
- success: true,
- };
- };
-
constructor() {
// Rehydrate
let data = {};
@@ -123,7 +71,6 @@ class AuthStore {
}
this.user = data.user;
this.team = data.team;
- this.oauthState = data.oauthState;
// load token from state for backwards compatability with
// sessions created pre-google auth
diff --git a/server/auth/slack.js b/server/auth/slack.js
index ac1eb89fa..eabd20af2 100644
--- a/server/auth/slack.js
+++ b/server/auth/slack.js
@@ -2,7 +2,6 @@
import Router from 'koa-router';
import addHours from 'date-fns/add_hours';
import addMonths from 'date-fns/add_months';
-import auth from '../middlewares/authentication';
import { slackAuth } from '../../shared/utils/routeHelpers';
import { Authentication, Integration, User, Team } from '../models';
import * as Slack from '../slack';
@@ -75,17 +74,19 @@ router.get('slack.callback', async ctx => {
ctx.redirect('/');
});
-router.post('slack.commands', auth(), async ctx => {
- const { code } = ctx.body;
+router.get('slack.commands', async ctx => {
+ const { code } = ctx.request.query;
ctx.assertPresent(code, 'code is required');
- const user = ctx.state.user;
const endpoint = `${process.env.URL || ''}/auth/slack.commands`;
const data = await Slack.oauthAccess(code, endpoint);
- const serviceId = 'slack';
+ const user = await User.find({
+ service: 'slack',
+ serviceId: data.user_id,
+ });
const authentication = await Authentication.create({
- serviceId,
+ serviceId: 'slack',
userId: user.id,
teamId: user.teamId,
token: data.access_token,
@@ -93,25 +94,33 @@ router.post('slack.commands', auth(), async ctx => {
});
await Integration.create({
- serviceId,
+ serviceId: 'slack',
type: 'command',
userId: user.id,
teamId: user.teamId,
authenticationId: authentication.id,
});
+
+ ctx.redirect('/settings/integrations/slack');
});
-router.post('slack.post', auth(), async ctx => {
- const { code, collectionId } = ctx.body;
+router.get('slack.post', async ctx => {
+ const { code, state } = ctx.request.query;
ctx.assertPresent(code, 'code is required');
- const user = ctx.state.user;
+ const collectionId = state;
+ ctx.assertUuid(collectionId, 'collectionId must be an uuid');
+
const endpoint = `${process.env.URL || ''}/auth/slack.post`;
const data = await Slack.oauthAccess(code, endpoint);
- const serviceId = 'slack';
+
+ const user = await User.find({
+ service: 'slack',
+ serviceId: data.user_id,
+ });
const authentication = await Authentication.create({
- serviceId,
+ serviceId: 'slack',
userId: user.id,
teamId: user.teamId,
token: data.access_token,
@@ -119,7 +128,7 @@ router.post('slack.post', auth(), async ctx => {
});
await Integration.create({
- serviceId,
+ serviceId: 'slack',
type: 'post',
userId: user.id,
teamId: user.teamId,
@@ -132,6 +141,8 @@ router.post('slack.post', auth(), async ctx => {
channelId: data.incoming_webhook.channel_id,
},
});
+
+ ctx.redirect('/settings/integrations/slack');
});
export default router;