diff --git a/server/auth/providers/google.js b/server/auth/providers/google.js index 71f124acf..c6fdf191d 100644 --- a/server/auth/providers/google.js +++ b/server/auth/providers/google.js @@ -30,69 +30,71 @@ export const config = { enabled: !!GOOGLE_CLIENT_ID, }; -passport.use( - new GoogleStrategy( - { - clientID: GOOGLE_CLIENT_ID, - clientSecret: GOOGLE_CLIENT_SECRET, - callbackURL: `${env.URL}/auth/google.callback`, - prompt: "select_account consent", - passReqToCallback: true, - store: new StateStore(), - scope: scopes, - }, - async function (req, accessToken, refreshToken, profile, done) { - try { - const domain = profile._json.hd; +if (GOOGLE_CLIENT_ID) { + passport.use( + new GoogleStrategy( + { + clientID: GOOGLE_CLIENT_ID, + clientSecret: GOOGLE_CLIENT_SECRET, + callbackURL: `${env.URL}/auth/google.callback`, + prompt: "select_account consent", + passReqToCallback: true, + store: new StateStore(), + scope: scopes, + }, + async function (req, accessToken, refreshToken, profile, done) { + try { + const domain = profile._json.hd; - if (!domain) { - throw new GoogleWorkspaceRequiredError(); + if (!domain) { + throw new GoogleWorkspaceRequiredError(); + } + + if (allowedDomains.length && !allowedDomains.includes(domain)) { + throw new GoogleWorkspaceInvalidError(); + } + + const subdomain = domain.split(".")[0]; + const teamName = capitalize(subdomain); + + const result = await accountProvisioner({ + ip: req.ip, + team: { + name: teamName, + domain, + subdomain, + }, + user: { + name: profile.displayName, + email: profile.email, + avatarUrl: profile.picture, + }, + authenticationProvider: { + name: providerName, + providerId: domain, + }, + authentication: { + providerId: profile.id, + accessToken, + refreshToken, + scopes, + }, + }); + return done(null, result.user, result); + } catch (err) { + return done(err, null); } - - if (allowedDomains.length && !allowedDomains.includes(domain)) { - throw new GoogleWorkspaceInvalidError(); - } - - const subdomain = domain.split(".")[0]; - const teamName = capitalize(subdomain); - - const result = await accountProvisioner({ - ip: req.ip, - team: { - name: teamName, - domain, - subdomain, - }, - user: { - name: profile.displayName, - email: profile.email, - avatarUrl: profile.picture, - }, - authenticationProvider: { - name: providerName, - providerId: domain, - }, - authentication: { - providerId: profile.id, - accessToken, - refreshToken, - scopes, - }, - }); - return done(null, result.user, result); - } catch (err) { - return done(err, null); } - } - ) -); + ) + ); -router.get("google", passport.authenticate(providerName)); + router.get("google", passport.authenticate(providerName)); -router.get( - "google.callback", - auth({ required: false }), - passportMiddleware(providerName) -); + router.get( + "google.callback", + auth({ required: false }), + passportMiddleware(providerName) + ); +} export default router; diff --git a/server/auth/providers/slack.js b/server/auth/providers/slack.js index 15b3cc961..b86d6ff24 100644 --- a/server/auth/providers/slack.js +++ b/server/auth/providers/slack.js @@ -27,77 +27,138 @@ export const config = { enabled: !!SLACK_CLIENT_ID, }; -const strategy = new SlackStrategy( - { - clientID: SLACK_CLIENT_ID, - clientSecret: SLACK_CLIENT_SECRET, - callbackURL: `${env.URL}/auth/slack.callback`, - passReqToCallback: true, - store: new StateStore(), - scope: scopes, - }, - async function (req, accessToken, refreshToken, profile, done) { - try { - const result = await accountProvisioner({ - ip: req.ip, - team: { - name: profile.team.name, - subdomain: profile.team.domain, - avatarUrl: profile.team.image_230, - }, - user: { - name: profile.user.name, - email: profile.user.email, - avatarUrl: profile.user.image_192, - }, - authenticationProvider: { - name: providerName, - providerId: profile.team.id, - }, - authentication: { - providerId: profile.user.id, - accessToken, - refreshToken, - scopes, - }, - }); - return done(null, result.user, result); - } catch (err) { - return done(err, null); - } - } -); - -// For some reason the author made the strategy name capatilised, I don't know -// why but we need everything lowercase so we just monkey-patch it here. -strategy.name = providerName; -passport.use(strategy); - -router.get("slack", passport.authenticate(providerName)); - -router.get( - "slack.callback", - auth({ required: false }), - passportMiddleware(providerName) -); - -router.get("slack.commands", auth({ required: false }), async (ctx) => { - const { code, state, error } = ctx.request.query; - const user = ctx.state.user; - ctx.assertPresent(code || error, "code is required"); - - if (error) { - ctx.redirect(`/settings/integrations/slack?error=${error}`); - return; - } - - // this code block accounts for the root domain being unable to - // access authentication for subdomains. We must forward to the appropriate - // subdomain to complete the oauth flow - if (!user) { - if (state) { +if (SLACK_CLIENT_ID) { + const strategy = new SlackStrategy( + { + clientID: SLACK_CLIENT_ID, + clientSecret: SLACK_CLIENT_SECRET, + callbackURL: `${env.URL}/auth/slack.callback`, + passReqToCallback: true, + store: new StateStore(), + scope: scopes, + }, + async function (req, accessToken, refreshToken, profile, done) { try { - const team = await Team.findByPk(state); + const result = await accountProvisioner({ + ip: req.ip, + team: { + name: profile.team.name, + subdomain: profile.team.domain, + avatarUrl: profile.team.image_230, + }, + user: { + name: profile.user.name, + email: profile.user.email, + avatarUrl: profile.user.image_192, + }, + authenticationProvider: { + name: providerName, + providerId: profile.team.id, + }, + authentication: { + providerId: profile.user.id, + accessToken, + refreshToken, + scopes, + }, + }); + return done(null, result.user, result); + } catch (err) { + return done(err, null); + } + } + ); + + // For some reason the author made the strategy name capatilised, I don't know + // why but we need everything lowercase so we just monkey-patch it here. + strategy.name = providerName; + passport.use(strategy); + + router.get("slack", passport.authenticate(providerName)); + + router.get( + "slack.callback", + auth({ required: false }), + passportMiddleware(providerName) + ); + + router.get("slack.commands", auth({ required: false }), async (ctx) => { + const { code, state, error } = ctx.request.query; + const user = ctx.state.user; + ctx.assertPresent(code || error, "code is required"); + + if (error) { + ctx.redirect(`/settings/integrations/slack?error=${error}`); + return; + } + + // this code block accounts for the root domain being unable to + // access authentication for subdomains. We must forward to the appropriate + // subdomain to complete the oauth flow + if (!user) { + if (state) { + try { + const team = await Team.findByPk(state); + return ctx.redirect( + `${team.url}/auth${ctx.request.path}?${ctx.request.querystring}` + ); + } catch (err) { + return ctx.redirect( + `/settings/integrations/slack?error=unauthenticated` + ); + } + } else { + return ctx.redirect( + `/settings/integrations/slack?error=unauthenticated` + ); + } + } + + const endpoint = `${process.env.URL || ""}/auth/slack.commands`; + const data = await Slack.oauthAccess(code, endpoint); + + const authentication = await Authentication.create({ + service: "slack", + userId: user.id, + teamId: user.teamId, + token: data.access_token, + scopes: data.scope.split(","), + }); + + await Integration.create({ + service: "slack", + type: "command", + userId: user.id, + teamId: user.teamId, + authenticationId: authentication.id, + settings: { + serviceTeamId: data.team_id, + }, + }); + + ctx.redirect("/settings/integrations/slack"); + }); + + router.get("slack.post", auth({ required: false }), async (ctx) => { + const { code, error, state } = ctx.request.query; + const user = ctx.state.user; + ctx.assertPresent(code || error, "code is required"); + + const collectionId = state; + ctx.assertUuid(collectionId, "collectionId must be an uuid"); + + if (error) { + ctx.redirect(`/settings/integrations/slack?error=${error}`); + return; + } + + // this code block accounts for the root domain being unable to + // access authentcation for subdomains. We must forward to the + // appropriate subdomain to complete the oauth flow + if (!user) { + try { + const collection = await Collection.findByPk(state); + const team = await Team.findByPk(collection.teamId); return ctx.redirect( `${team.url}/auth${ctx.request.path}?${ctx.request.querystring}` ); @@ -106,91 +167,36 @@ router.get("slack.commands", auth({ required: false }), async (ctx) => { `/settings/integrations/slack?error=unauthenticated` ); } - } else { - return ctx.redirect(`/settings/integrations/slack?error=unauthenticated`); } - } - const endpoint = `${process.env.URL || ""}/auth/slack.commands`; - const data = await Slack.oauthAccess(code, endpoint); + const endpoint = `${process.env.URL || ""}/auth/slack.post`; + const data = await Slack.oauthAccess(code, endpoint); - const authentication = await Authentication.create({ - service: "slack", - userId: user.id, - teamId: user.teamId, - token: data.access_token, - scopes: data.scope.split(","), + const authentication = await Authentication.create({ + service: "slack", + userId: user.id, + teamId: user.teamId, + token: data.access_token, + scopes: data.scope.split(","), + }); + + await Integration.create({ + service: "slack", + type: "post", + userId: user.id, + teamId: user.teamId, + authenticationId: authentication.id, + collectionId, + events: [], + settings: { + url: data.incoming_webhook.url, + channel: data.incoming_webhook.channel, + channelId: data.incoming_webhook.channel_id, + }, + }); + + ctx.redirect("/settings/integrations/slack"); }); - - await Integration.create({ - service: "slack", - type: "command", - userId: user.id, - teamId: user.teamId, - authenticationId: authentication.id, - settings: { - serviceTeamId: data.team_id, - }, - }); - - ctx.redirect("/settings/integrations/slack"); -}); - -router.get("slack.post", auth({ required: false }), async (ctx) => { - const { code, error, state } = ctx.request.query; - const user = ctx.state.user; - ctx.assertPresent(code || error, "code is required"); - - const collectionId = state; - ctx.assertUuid(collectionId, "collectionId must be an uuid"); - - if (error) { - ctx.redirect(`/settings/integrations/slack?error=${error}`); - return; - } - - // this code block accounts for the root domain being unable to - // access authentcation for subdomains. We must forward to the - // appropriate subdomain to complete the oauth flow - if (!user) { - try { - const collection = await Collection.findByPk(state); - const team = await Team.findByPk(collection.teamId); - return ctx.redirect( - `${team.url}/auth${ctx.request.path}?${ctx.request.querystring}` - ); - } catch (err) { - return ctx.redirect(`/settings/integrations/slack?error=unauthenticated`); - } - } - - const endpoint = `${process.env.URL || ""}/auth/slack.post`; - const data = await Slack.oauthAccess(code, endpoint); - - const authentication = await Authentication.create({ - service: "slack", - userId: user.id, - teamId: user.teamId, - token: data.access_token, - scopes: data.scope.split(","), - }); - - await Integration.create({ - service: "slack", - type: "post", - userId: user.id, - teamId: user.teamId, - authenticationId: authentication.id, - collectionId, - events: [], - settings: { - url: data.incoming_webhook.url, - channel: data.incoming_webhook.channel, - channelId: data.incoming_webhook.channel_id, - }, - }); - - ctx.redirect("/settings/integrations/slack"); -}); +} export default router;