Working direct install flow

This commit is contained in:
Tom Moor
2017-11-21 23:51:31 -08:00
parent 13623cb1b3
commit dd2cd2f9d8
7 changed files with 63 additions and 64 deletions

View File

@ -1,47 +1,22 @@
// @flow
import React from 'react';
import { observer, inject } from 'mobx-react';
import { inject } from 'mobx-react';
import { slackAuth } from 'shared/utils/routeHelpers';
import AuthStore from 'stores/AuthStore';
type Props = {
children: React$Element<*>,
scopes?: string[],
auth: AuthStore,
redirectUri: string,
scopes?: string[],
redirectUri?: string,
};
@observer
class SlackAuthLink extends React.Component {
props: Props;
static defaultProps = {
scopes: [
'identity.email',
'identity.basic',
'identity.avatar',
'identity.team',
],
};
slackUrl = () => {
const baseUrl = 'https://slack.com/oauth/authorize';
const params = {
client_id: SLACK_KEY,
scope: this.props.scopes ? this.props.scopes.join(' ') : '',
redirect_uri: this.props.redirectUri || SLACK_REDIRECT_URI,
state: this.props.auth.getOauthState(),
};
const urlParams = Object.keys(params)
.map(key => `${key}=${encodeURIComponent(params[key])}`)
.join('&');
return `${baseUrl}?${urlParams}`;
};
render() {
return <a href={this.slackUrl()}>{this.props.children}</a>;
}
function SlackAuthLink({ auth, children, scopes, redirectUri }: Props) {
return (
<a href={slackAuth(this.props.auth.getOauthState(), scopes, redirectUri)}>
{children}
</a>
);
}
export default inject('auth')(SlackAuthLink);

View File

@ -6,7 +6,7 @@ import queryString from 'query-string';
import { observable } from 'mobx';
import { observer, inject } from 'mobx-react';
import { client } from 'utils/ApiClient';
import { slackAuth } from 'utils/routeHelpers';
import { slackAuth } from 'shared/utils/routeHelpers';
import AuthStore from 'stores/AuthStore';

View File

@ -53,7 +53,10 @@ class AuthStore {
@action
authWithSlack = async (code: string, state: string) => {
if (state !== this.oauthState) {
// 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', { path: '/' });
if (state !== this.oauthState && state !== serverState) {
return {
success: false,
};
@ -68,6 +71,9 @@ class AuthStore {
};
}
// 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'

View File

@ -22,31 +22,6 @@ export function documentUrl(doc: Document): string {
return doc.url;
}
export function slackAuth(
state: string,
scopes: string[] = [
'identity.email',
'identity.basic',
'identity.avatar',
'identity.team',
],
redirectUri: string = `${BASE_URL}/auth/slack`
): string {
const baseUrl = 'https://slack.com/oauth/authorize';
const params = {
client_id: SLACK_KEY,
scope: scopes ? scopes.join(' ') : '',
redirect_uri: redirectUri,
state,
};
const urlParams = Object.keys(params)
.map(key => `${key}=${encodeURIComponent(params[key])}`)
.join('&');
return `${baseUrl}?${urlParams}`;
}
export function documentNewUrl(doc: Document): string {
const newUrl = `${doc.collection.url}/new`;
if (doc.parentDocumentId) {

View File

@ -8,6 +8,7 @@ import sendfile from 'koa-sendfile';
import serve from 'koa-static';
import subdomainRedirect from './middlewares/subdomainRedirect';
import renderpage from './utils/renderpage';
import { slackAuth } from '../shared/utils/routeHelpers';
import Home from './pages/Home';
import About from './pages/About';
@ -44,6 +45,19 @@ if (process.env.NODE_ENV === 'production') {
});
}
// slack direct install
router.get('/auth/slack/install', async ctx => {
const state = Math.random()
.toString(36)
.substring(7);
ctx.cookies.set('state', state, {
httpOnly: false,
expires: new Date('2100'),
});
ctx.redirect(slackAuth(state));
});
// static pages
router.get('/about', ctx => renderpage(ctx, <About />));
router.get('/pricing', ctx => renderpage(ctx, <Pricing />));

View File

@ -0,0 +1,26 @@
// @flow
export function slackAuth(
state: string,
scopes: string[] = [
'identity.email',
'identity.basic',
'identity.avatar',
'identity.team',
],
redirectUri: string = `${process.env.URL}/auth/slack`
): string {
const baseUrl = 'https://slack.com/oauth/authorize';
const params = {
client_id: process.env.SLACK_KEY,
scope: scopes ? scopes.join(' ') : '',
redirect_uri: redirectUri,
state,
};
const urlParams = Object.keys(params)
.map(key => `${key}=${encodeURIComponent(params[key])}`)
.join('&');
return `${baseUrl}?${urlParams}`;
}

View File

@ -11,10 +11,13 @@ const definePlugin = new webpack.DefinePlugin({
JSON.parse(process.env.BUILD_PRERELEASE || 'false')
),
SLACK_REDIRECT_URI: JSON.stringify(process.env.SLACK_REDIRECT_URI),
SLACK_KEY: JSON.stringify(process.env.SLACK_KEY),
BASE_URL: JSON.stringify(process.env.URL),
BUGSNAG_KEY: JSON.stringify(process.env.BUGSNAG_KEY),
DEPLOYMENT: JSON.stringify(process.env.DEPLOYMENT || 'hosted')
DEPLOYMENT: JSON.stringify(process.env.DEPLOYMENT || 'hosted'),
'process.env': {
URL: JSON.stringify(process.env.URL),
SLACK_KEY: JSON.stringify(process.env.SLACK_KEY),
}
});
module.exports = {