Uses vercel url on integration endpoints for staging (#1293)

* Legibility and base url fixes

* Uses vercel url on integration endpoints for staging

* We validate the user before creating credentials
This commit is contained in:
Omar López 2021-12-10 14:14:54 -07:00 committed by GitHub
parent 3ff99f7877
commit 3587e1ac9c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 80 additions and 72 deletions

View file

@ -1,48 +1,47 @@
import type { NextApiRequest, NextApiResponse } from "next"; import type { NextApiRequest, NextApiResponse } from "next";
import { getSession } from "next-auth/client";
import { getSession } from "@lib/auth";
import { symmetricEncrypt } from "@lib/crypto"; import { symmetricEncrypt } from "@lib/crypto";
import { AppleCalendar } from "@lib/integrations/Apple/AppleCalendarAdapter"; import { AppleCalendar } from "@lib/integrations/Apple/AppleCalendarAdapter";
import logger from "@lib/logger"; import logger from "@lib/logger";
import prisma from "@lib/prisma";
import prisma from "../../../../lib/prisma";
export default async function handler(req: NextApiRequest, res: NextApiResponse) { export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === "POST") { if (req.method === "POST") {
// Check that user is authenticated // Check that user is authenticated
const session = await getSession({ req: req }); const session = await getSession({ req });
if (!session) { if (!session?.user?.id) {
res.status(401).json({ message: "You must be logged in to do this" }); res.status(401).json({ message: "You must be logged in to do this" });
return; return;
} }
const { username, password } = req.body; const { username, password } = req.body;
// Get user // Get user
await prisma.user.findFirst({ const user = await prisma.user.findFirst({
rejectOnNotFound: true,
where: { where: {
email: session.user.email, id: session?.user?.id,
}, },
select: { select: {
id: true, id: true,
}, },
}); });
const data = {
type: "apple_calendar",
key: symmetricEncrypt(JSON.stringify({ username, password }), process.env.CALENDSO_ENCRYPTION_KEY!),
userId: user.id,
};
try { try {
const dav = new AppleCalendar({ const dav = new AppleCalendar({
id: 0, id: 0,
type: "apple_calendar", ...data,
key: symmetricEncrypt(JSON.stringify({ username, password }), process.env.CALENDSO_ENCRYPTION_KEY),
userId: session.user.id,
}); });
await dav.listCalendars(); await dav.listCalendars();
await prisma.credential.create({ await prisma.credential.create({
data: { data,
type: "apple_calendar",
key: symmetricEncrypt(JSON.stringify({ username, password }), process.env.CALENDSO_ENCRYPTION_KEY),
userId: session.user.id,
},
}); });
} catch (reason) { } catch (reason) {
logger.error("Could not add this caldav account", reason); logger.error("Could not add this caldav account", reason);

View file

@ -4,51 +4,47 @@ import { getSession } from "@lib/auth";
import { symmetricEncrypt } from "@lib/crypto"; import { symmetricEncrypt } from "@lib/crypto";
import { CalDavCalendar } from "@lib/integrations/CalDav/CalDavCalendarAdapter"; import { CalDavCalendar } from "@lib/integrations/CalDav/CalDavCalendarAdapter";
import logger from "@lib/logger"; import logger from "@lib/logger";
import prisma from "@lib/prisma";
import prisma from "../../../../lib/prisma";
export default async function handler(req: NextApiRequest, res: NextApiResponse) { export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === "POST") { if (req.method === "POST") {
// Check that user is authenticated // Check that user is authenticated
const session = await getSession({ req: req }); const session = await getSession({ req });
if (!session) { if (!session?.user?.id) {
res.status(401).json({ message: "You must be logged in to do this" }); res.status(401).json({ message: "You must be logged in to do this" });
return; return;
} }
const { username, password, url } = req.body; const { username, password, url } = req.body;
// Get user // Get user
await prisma.user.findFirst({ const user = await prisma.user.findFirst({
rejectOnNotFound: true,
where: { where: {
email: session.user.email, id: session?.user?.id,
}, },
select: { select: {
id: true, id: true,
}, },
}); });
const data = {
type: "caldav_calendar",
key: symmetricEncrypt(
JSON.stringify({ username, password, url }),
process.env.CALENDSO_ENCRYPTION_KEY!
),
userId: user.id,
};
try { try {
const dav = new CalDavCalendar({ const dav = new CalDavCalendar({
id: 0, id: 0,
type: "caldav_calendar", ...data,
key: symmetricEncrypt(
JSON.stringify({ username, password, url }),
process.env.CALENDSO_ENCRYPTION_KEY
),
userId: session.user.id,
}); });
await dav.listCalendars(); await dav.listCalendars();
await prisma.credential.create({ await prisma.credential.create({
data: { data,
type: "caldav_calendar",
key: symmetricEncrypt(
JSON.stringify({ username, password, url }),
process.env.CALENDSO_ENCRYPTION_KEY
),
userId: session.user.id,
},
}); });
} catch (reason) { } catch (reason) {
logger.error("Could not add this caldav account", reason); logger.error("Could not add this caldav account", reason);

View file

@ -2,6 +2,7 @@ import { google } from "googleapis";
import type { NextApiRequest, NextApiResponse } from "next"; import type { NextApiRequest, NextApiResponse } from "next";
import { getSession } from "@lib/auth"; import { getSession } from "@lib/auth";
import { BASE_URL } from "@lib/config/constants";
import { encodeOAuthState } from "../utils"; import { encodeOAuthState } from "../utils";
@ -23,7 +24,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
// Get token from Google Calendar API // Get token from Google Calendar API
const { client_secret, client_id } = JSON.parse(credentials).web; const { client_secret, client_id } = JSON.parse(credentials).web;
const redirect_uri = process.env.BASE_URL + "/api/integrations/googlecalendar/callback"; const redirect_uri = BASE_URL + "/api/integrations/googlecalendar/callback";
const oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uri); const oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uri);
const authUrl = oAuth2Client.generateAuthUrl({ const authUrl = oAuth2Client.generateAuthUrl({

View file

@ -2,6 +2,7 @@ import { google } from "googleapis";
import type { NextApiRequest, NextApiResponse } from "next"; import type { NextApiRequest, NextApiResponse } from "next";
import { getSession } from "@lib/auth"; import { getSession } from "@lib/auth";
import { BASE_URL } from "@lib/config/constants";
import prisma from "@lib/prisma"; import prisma from "@lib/prisma";
import { decodeOAuthState } from "../utils"; import { decodeOAuthState } from "../utils";
@ -28,7 +29,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
} }
const { client_secret, client_id } = JSON.parse(credentials).web; const { client_secret, client_id } = JSON.parse(credentials).web;
const redirect_uri = process.env.BASE_URL + "/api/integrations/googlecalendar/callback"; const redirect_uri = BASE_URL + "/api/integrations/googlecalendar/callback";
const oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uri); const oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uri);
const token = await oAuth2Client.getToken(code); const token = await oAuth2Client.getToken(code);

View file

@ -1,6 +1,8 @@
import type { NextApiRequest, NextApiResponse } from "next"; import type { NextApiRequest, NextApiResponse } from "next";
import { stringify } from "querystring";
import { getSession } from "@lib/auth"; import { getSession } from "@lib/auth";
import { BASE_URL } from "@lib/config/constants";
import { encodeOAuthState } from "../utils"; import { encodeOAuthState } from "../utils";
@ -9,7 +11,7 @@ const scopes = ["User.Read", "Calendars.Read", "Calendars.ReadWrite", "offline_a
export default async function handler(req: NextApiRequest, res: NextApiResponse) { export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === "GET") { if (req.method === "GET") {
// Check that user is authenticated // Check that user is authenticated
const session = await getSession({ req: req }); const session = await getSession({ req });
if (!session?.user) { if (!session?.user) {
res.status(401).json({ message: "You must be logged in to do this" }); res.status(401).json({ message: "You must be logged in to do this" });
@ -17,17 +19,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
} }
const state = encodeOAuthState(req); const state = encodeOAuthState(req);
let url = const params = {
"https://login.microsoftonline.com/common/oauth2/v2.0/authorize?response_type=code&scope=" + response_type: "code",
scopes.join(" ") + scope: scopes.join(" "),
"&client_id=" + client_id: process.env.MS_GRAPH_CLIENT_ID,
process.env.MS_GRAPH_CLIENT_ID + redirect_uri: BASE_URL + "/api/integrations/office365calendar/callback",
"&redirect_uri=" + state,
process.env.BASE_URL + };
"/api/integrations/office365calendar/callback"; const query = stringify(params);
if (state) { const url = `https://login.microsoftonline.com/common/oauth2/v2.0/authorize?${query}`;
url += "&state=" + encodeURIComponent(state);
}
res.status(200).json({ url }); res.status(200).json({ url });
} }
} }

View file

@ -1,6 +1,7 @@
import type { NextApiRequest, NextApiResponse } from "next"; import type { NextApiRequest, NextApiResponse } from "next";
import { getSession } from "@lib/auth"; import { getSession } from "@lib/auth";
import { BASE_URL } from "@lib/config/constants";
import prisma from "../../../../lib/prisma"; import prisma from "../../../../lib/prisma";
import { decodeOAuthState } from "../utils"; import { decodeOAuthState } from "../utils";
@ -31,7 +32,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
grant_type: "authorization_code", grant_type: "authorization_code",
code, code,
scope: scopes.join(" "), scope: scopes.join(" "),
redirect_uri: process.env.BASE_URL + "/api/integrations/office365calendar/callback", redirect_uri: BASE_URL + "/api/integrations/office365calendar/callback",
client_secret: process.env.MS_GRAPH_CLIENT_SECRET!, client_secret: process.env.MS_GRAPH_CLIENT_SECRET!,
}); });

View file

@ -1,38 +1,40 @@
import type { NextApiRequest, NextApiResponse } from "next"; import type { NextApiRequest, NextApiResponse } from "next";
import { stringify } from "querystring";
import { getSession } from "@lib/auth"; import { getSession } from "@lib/auth";
import { BASE_URL } from "@lib/config/constants";
import prisma from "../../../../lib/prisma"; import prisma from "@lib/prisma";
const client_id = process.env.ZOOM_CLIENT_ID; const client_id = process.env.ZOOM_CLIENT_ID;
export default async function handler(req: NextApiRequest, res: NextApiResponse) { export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === "GET") { if (req.method === "GET") {
// Check that user is authenticated // Check that user is authenticated
const session = await getSession({ req: req }); const session = await getSession({ req });
if (!session) { if (!session?.user?.id) {
res.status(401).json({ message: "You must be logged in to do this" }); res.status(401).json({ message: "You must be logged in to do this" });
return; return;
} }
// Get user // Get user
await prisma.user.findFirst({ await prisma.user.findFirst({
rejectOnNotFound: true,
where: { where: {
email: session.user.email, id: session?.user?.id,
}, },
select: { select: {
id: true, id: true,
}, },
}); });
const redirectUri = encodeURI(process.env.BASE_URL + "/api/integrations/zoomvideo/callback"); const params = {
const authUrl = response_type: "code",
"https://zoom.us/oauth/authorize?response_type=code&client_id=" + client_id,
client_id + redirect_uri: BASE_URL + "/api/integrations/zoomvideo/callback",
"&redirect_uri=" + };
redirectUri; const query = stringify(params);
const url = `https://zoom.us/oauth/authorize?${query}`;
res.status(200).json({ url: authUrl }); res.status(200).json({ url });
} }
} }

View file

@ -1,6 +1,7 @@
import type { NextApiRequest, NextApiResponse } from "next"; import type { NextApiRequest, NextApiResponse } from "next";
import { getSession } from "@lib/auth"; import { getSession } from "@lib/auth";
import { BASE_URL } from "@lib/config/constants";
import prisma from "../../../../lib/prisma"; import prisma from "../../../../lib/prisma";
@ -11,14 +12,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const { code } = req.query; const { code } = req.query;
// Check that user is authenticated // Check that user is authenticated
const session = await getSession({ req: req }); const session = await getSession({ req });
if (!session) { if (!session?.user?.id) {
res.status(401).json({ message: "You must be logged in to do this" }); res.status(401).json({ message: "You must be logged in to do this" });
return; return;
} }
const redirectUri = encodeURI(process.env.BASE_URL + "/api/integrations/zoomvideo/callback"); const redirectUri = encodeURI(BASE_URL + "/api/integrations/zoomvideo/callback");
const authHeader = "Basic " + Buffer.from(client_id + ":" + client_secret).toString("base64"); const authHeader = "Basic " + Buffer.from(client_id + ":" + client_secret).toString("base64");
const result = await fetch( const result = await fetch(
"https://zoom.us/oauth/token?grant_type=authorization_code&code=" + code + "&redirect_uri=" + redirectUri, "https://zoom.us/oauth/token?grant_type=authorization_code&code=" + code + "&redirect_uri=" + redirectUri,
@ -31,12 +32,19 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
); );
const json = await result.json(); const json = await result.json();
await prisma.credential.create({ await prisma.user.update({
where: {
id: session.user.id,
},
data: { data: {
type: "zoom_video", credentials: {
key: json, create: {
userId: session.user.id, type: "zoom_video",
key: json,
},
},
}, },
}); });
res.redirect("/integrations"); res.redirect("/integrations");
} }