Working direct install flow
This commit is contained in:
@ -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);
|
||||
|
@ -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';
|
||||
|
||||
|
@ -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'
|
||||
|
@ -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) {
|
||||
|
@ -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 />));
|
||||
|
26
shared/utils/routeHelpers.js
Normal file
26
shared/utils/routeHelpers.js
Normal 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}`;
|
||||
}
|
@ -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 = {
|
||||
|
Reference in New Issue
Block a user