import Router from 'koa-router'; import Sequelize from 'sequelize'; import apiError, { httpErrors } from '../errors'; import fetch from 'isomorphic-fetch'; import querystring from 'querystring'; import { presentUser, presentTeam } from '../presenters'; import { User, Team } from '../models'; const router = new Router(); router.post('auth.signup', async (ctx) => { const { username, name, email, password } = ctx.request.body; ctx.assertPresent(username, 'name is required'); ctx.assertPresent(name, 'name is required'); ctx.assertPresent(email, 'email is required'); ctx.assertEmail(email, 'email is invalid'); ctx.assertPresent(password, 'password is required'); if (await User.findOne({ where: { email } })) { throw apiError(400, 'user_exists_with_email', 'User already exists with this email'); } if (await User.findOne({ where: { username } })) { throw apiError(400, 'user_exists_with_username', 'User already exists with this username'); } const user = await User.create({ username, name, email, password, }); ctx.body = { data: { user: await presentUser(ctx, user), accessToken: user.getJwtToken(), } }; }); router.post('auth.login', async (ctx) => { const { username, password } = ctx.request.body; ctx.assertPresent(username, 'username/email is required'); ctx.assertPresent(password, 'password is required'); let user; if (username) { user = await User.findOne({ where: Sequelize.or( { email: username }, { username }, ) }); } else { throw apiError(400, 'invalid_credentials', 'username or email is invalid'); } if (!user) { throw apiError(400, 'username or email is invalid'); } if (!user.passwordDigest) { throw apiError(400, 'no_password', 'No password set'); } if (!await user.verifyPassword(password)) { throw apiError(400, 'invalid_password', 'Invalid password'); } ctx.body = { data: { user: await presentUser(ctx, user), accessToken: user.getJwtToken(), } }; }); router.post('auth.slack', async (ctx) => { const { code } = ctx.body; ctx.assertPresent(code, 'code is required'); const body = { client_id: process.env.SLACK_KEY, client_secret: process.env.SLACK_SECRET, redirect_uri: `${process.env.URL}/auth/slack`, code, }; let data; try { const response = await fetch(`https://slack.com/api/oauth.access?${querystring.stringify(body)}`); data = await response.json(); } catch (e) { throw httpErrors.BadRequest(); } if (!data.ok) throw httpErrors.BadRequest(data.error); // Temp to block const allowedSlackDomains = process.env.ALLOWED_SLACK_DOMAINS.split(','); if (!allowedSlackDomains.includes(data.team.domain)) { throw apiError(400, 'invalid_slack_team', 'Atlas is currently in private beta'); } // User let user = await User.findOne({ where: { slackId: data.user.id } }); // Team let team = await Team.findOne({ where: { slackId: data.team.id } }); const teamExisted = !!team; if (!team) { team = await Team.create({ name: data.team.name, slackId: data.team.id, slackData: data.team, }); } else { team.name = data.team.name; team.slackData = data.team; team = await team.save(); } if (user) { user.slackAccessToken = data.access_token; user.slackData = data.user; await user.save(); } else { user = await User.create({ slackId: data.user.id, username: data.user.name, name: data.user.name, email: data.user.email, teamId: team.id, slackData: data.user, slackAccessToken: data.access_token, }); } if (!teamExisted) { await team.createFirstAtlas(user.id); } ctx.body = { data: { user: await presentUser(ctx, user), team: await presentTeam(ctx, team), accessToken: user.getJwtToken(), } }; }); router.post('auth.slackCommands', async (ctx) => { const { code } = ctx.body; ctx.assertPresent(code, 'code is required'); const body = { client_id: process.env.SLACK_KEY, client_secret: process.env.SLACK_SECRET, redirect_uri: `${process.env.URL}/auth/slack/commands`, code, }; let data; try { const response = await fetch(`https://slack.com/api/oauth.access?${querystring.stringify(body)}`); data = await response.json(); } catch (e) { throw httpErrors.BadRequest(); } if (!data.ok) throw httpErrors.BadRequest(data.error); }); export default router;