Working direct install flow
This commit is contained in:
@ -1,47 +1,22 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
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';
|
import AuthStore from 'stores/AuthStore';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
children: React$Element<*>,
|
children: React$Element<*>,
|
||||||
scopes?: string[],
|
|
||||||
auth: AuthStore,
|
auth: AuthStore,
|
||||||
redirectUri: string,
|
scopes?: string[],
|
||||||
|
redirectUri?: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
@observer
|
function SlackAuthLink({ auth, children, scopes, redirectUri }: Props) {
|
||||||
class SlackAuthLink extends React.Component {
|
return (
|
||||||
props: Props;
|
<a href={slackAuth(this.props.auth.getOauthState(), scopes, redirectUri)}>
|
||||||
|
{children}
|
||||||
static defaultProps = {
|
</a>
|
||||||
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>;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default inject('auth')(SlackAuthLink);
|
export default inject('auth')(SlackAuthLink);
|
||||||
|
@ -6,7 +6,7 @@ import queryString from 'query-string';
|
|||||||
import { observable } from 'mobx';
|
import { observable } from 'mobx';
|
||||||
import { observer, inject } from 'mobx-react';
|
import { observer, inject } from 'mobx-react';
|
||||||
import { client } from 'utils/ApiClient';
|
import { client } from 'utils/ApiClient';
|
||||||
import { slackAuth } from 'utils/routeHelpers';
|
import { slackAuth } from 'shared/utils/routeHelpers';
|
||||||
|
|
||||||
import AuthStore from 'stores/AuthStore';
|
import AuthStore from 'stores/AuthStore';
|
||||||
|
|
||||||
|
@ -53,7 +53,10 @@ class AuthStore {
|
|||||||
|
|
||||||
@action
|
@action
|
||||||
authWithSlack = async (code: string, state: string) => {
|
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 {
|
return {
|
||||||
success: false,
|
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(
|
invariant(
|
||||||
res && res.data && res.data.user && res.data.team && res.data.accessToken,
|
res && res.data && res.data.user && res.data.team && res.data.accessToken,
|
||||||
'All values should be available'
|
'All values should be available'
|
||||||
|
@ -22,31 +22,6 @@ export function documentUrl(doc: Document): string {
|
|||||||
return doc.url;
|
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 {
|
export function documentNewUrl(doc: Document): string {
|
||||||
const newUrl = `${doc.collection.url}/new`;
|
const newUrl = `${doc.collection.url}/new`;
|
||||||
if (doc.parentDocumentId) {
|
if (doc.parentDocumentId) {
|
||||||
|
@ -8,6 +8,7 @@ import sendfile from 'koa-sendfile';
|
|||||||
import serve from 'koa-static';
|
import serve from 'koa-static';
|
||||||
import subdomainRedirect from './middlewares/subdomainRedirect';
|
import subdomainRedirect from './middlewares/subdomainRedirect';
|
||||||
import renderpage from './utils/renderpage';
|
import renderpage from './utils/renderpage';
|
||||||
|
import { slackAuth } from '../shared/utils/routeHelpers';
|
||||||
|
|
||||||
import Home from './pages/Home';
|
import Home from './pages/Home';
|
||||||
import About from './pages/About';
|
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
|
// static pages
|
||||||
router.get('/about', ctx => renderpage(ctx, <About />));
|
router.get('/about', ctx => renderpage(ctx, <About />));
|
||||||
router.get('/pricing', ctx => renderpage(ctx, <Pricing />));
|
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')
|
JSON.parse(process.env.BUILD_PRERELEASE || 'false')
|
||||||
),
|
),
|
||||||
SLACK_REDIRECT_URI: JSON.stringify(process.env.SLACK_REDIRECT_URI),
|
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),
|
BASE_URL: JSON.stringify(process.env.URL),
|
||||||
BUGSNAG_KEY: JSON.stringify(process.env.BUGSNAG_KEY),
|
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 = {
|
module.exports = {
|
||||||
|
Reference in New Issue
Block a user