From a0e124d9efccccb101dec1e8f5c79128a8c8b4aa Mon Sep 17 00:00:00 2001 From: austinkelsay Date: Wed, 2 Oct 2024 16:58:36 -0500 Subject: [PATCH] Secure user endponts with session, dont require calling endpoints from nextauth, call models instead so we can completely secure the endpoints --- src/pages/api/auth/[...nextauth].js | 25 ++++++++----------- .../api/users/[slug]/courses/[courseSlug].js | 10 ++++++++ src/pages/api/users/[slug]/courses/index.js | 10 ++++++++ src/pages/api/users/[slug]/index.js | 9 +++++++ .../users/[slug]/lessons/[resourceSlug].js | 10 ++++++++ src/pages/api/users/[slug]/lessons/index.js | 10 ++++++++ .../api/users/[slug]/lightning-address.js | 9 +++++++ src/pages/api/users/[slug]/nip05.js | 9 +++++++ src/pages/api/users/index.js | 1 + src/pages/api/users/subscription/index.js | 9 +++++++ 10 files changed, 88 insertions(+), 14 deletions(-) diff --git a/src/pages/api/auth/[...nextauth].js b/src/pages/api/auth/[...nextauth].js index 4e80084..ecaf1c1 100644 --- a/src/pages/api/auth/[...nextauth].js +++ b/src/pages/api/auth/[...nextauth].js @@ -2,20 +2,16 @@ import NextAuth from "next-auth"; import CredentialsProvider from "next-auth/providers/credentials"; import EmailProvider from "next-auth/providers/email"; import NDK from "@nostr-dev-kit/ndk"; -import axios from "axios"; import { PrismaAdapter } from "@next-auth/prisma-adapter"; import prisma from "@/db/prisma"; import { findKind0Fields } from "@/utils/nostr"; import { generateSecretKey, getPublicKey } from 'nostr-tools/pure' import { bytesToHex } from '@noble/hashes/utils' -import { updateUser } from "@/db/models/userModels"; +import { updateUser, getUserByPubkey, createUser } from "@/db/models/userModels"; import { createRole } from "@/db/models/roleModels"; import appConfig from "@/config/appConfig"; // todo update EMAIL_FROM to be a plebdevs email - -const BACKEND_URL = process.env.BACKEND_URL; - const ndk = new NDK({ explicitRelayUrls: appConfig.defaultRelayUrls, }); @@ -28,24 +24,25 @@ const authorize = async (pubkey) => { const profile = await user.fetchProfile(); // Check if user exists, create if not - const response = await axios.get(`${BACKEND_URL}/api/users/${pubkey}`); - if (response.status === 200 && response.data) { + let dbUser = await getUserByPubkey(pubkey); + + if (dbUser) { const fields = await findKind0Fields(profile); // Combine user object with kind0Fields, giving priority to kind0Fields - const combinedUser = { ...response.data, ...fields }; + const combinedUser = { ...dbUser, ...fields }; - // Update the user on the backend if necessary - // await axios.put(`${BACKEND_URL}/api/users/${combinedUser.id}`, combinedUser); + // Update the user in the database if necessary + dbUser = await updateUser(dbUser.id, combinedUser); - return combinedUser; - } else if (response.status === 204) { + return dbUser; + } else { // Create user if (profile) { const fields = await findKind0Fields(profile); const payload = { pubkey, username: fields.username, avatar: fields.avatar }; - const createUserResponse = await axios.post(`${BACKEND_URL}/api/users`, payload); - return createUserResponse.data; + dbUser = await createUser(payload); + return dbUser; } } } catch (error) { diff --git a/src/pages/api/users/[slug]/courses/[courseSlug].js b/src/pages/api/users/[slug]/courses/[courseSlug].js index 6ec5572..ca59cda 100644 --- a/src/pages/api/users/[slug]/courses/[courseSlug].js +++ b/src/pages/api/users/[slug]/courses/[courseSlug].js @@ -1,9 +1,19 @@ import { checkCourseCompletion } from "@/db/models/userCourseModels"; +import { getServerSession } from "next-auth/next" +import { authOptions } from "@/pages/api/auth/[...nextauth].js" // todo somehow make it to where we can get lesson slug in this endpoint export default async function handler(req, res) { const { method } = req; const { slug, courseSlug } = req.query; + + const session = await getServerSession(req, res, authOptions); + + if (!session) { + res.status(401).json({ error: "Unauthorized" }); + return; + } + switch (method) { case "GET": try { diff --git a/src/pages/api/users/[slug]/courses/index.js b/src/pages/api/users/[slug]/courses/index.js index 086a2d9..d6e004b 100644 --- a/src/pages/api/users/[slug]/courses/index.js +++ b/src/pages/api/users/[slug]/courses/index.js @@ -1,9 +1,19 @@ import { createOrUpdateUserCourse } from "@/db/models/userCourseModels"; +import { getServerSession } from "next-auth/next" +import { authOptions } from "@/pages/api/auth/[...nextauth].js" export default async function handler(req, res) { const { method } = req; const { slug, courseSlug } = req.query; const userId = slug; + + const session = await getServerSession(req, res, authOptions); + + if (!session) { + res.status(401).json({ error: "Unauthorized" }); + return; + } + switch (method) { case "POST": try { diff --git a/src/pages/api/users/[slug]/index.js b/src/pages/api/users/[slug]/index.js index fe2fde1..4f123b0 100644 --- a/src/pages/api/users/[slug]/index.js +++ b/src/pages/api/users/[slug]/index.js @@ -1,4 +1,6 @@ import { getUserById, getUserByPubkey, getUserByEmail, updateUser, deleteUser } from "@/db/models/userModels"; +import { getServerSession } from "next-auth/next" +import { authOptions } from "@/pages/api/auth/[...nextauth].js" export default async function handler(req, res) { const { slug } = req.query; @@ -6,6 +8,13 @@ export default async function handler(req, res) { const isPubkey = /^[0-9a-fA-F]{64}$/.test(slug); const isEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(slug); + const session = await getServerSession(req, res, authOptions); + + if (!session) { + res.status(401).json({ error: "Unauthorized" }); + return; + } + try { let user; if (isPubkey) { diff --git a/src/pages/api/users/[slug]/lessons/[resourceSlug].js b/src/pages/api/users/[slug]/lessons/[resourceSlug].js index e91a99c..451d126 100644 --- a/src/pages/api/users/[slug]/lessons/[resourceSlug].js +++ b/src/pages/api/users/[slug]/lessons/[resourceSlug].js @@ -1,10 +1,20 @@ import { getUserLesson, createOrUpdateUserLesson, deleteUserLesson } from "@/db/models/userLessonModels"; import { getResourceById } from "@/db/models/resourceModels"; +import { getServerSession } from "next-auth/next" +import { authOptions } from "@/pages/api/auth/[...nextauth].js" // todo somehow make it to where we can get lesson slug in this endpoint export default async function handler(req, res) { const { method } = req; const { slug, resourceSlug, courseId } = req.query; + + const session = await getServerSession(req, res, authOptions); + + if (!session) { + res.status(401).json({ error: "Unauthorized" }); + return; + } + switch (method) { case "GET": try { diff --git a/src/pages/api/users/[slug]/lessons/index.js b/src/pages/api/users/[slug]/lessons/index.js index a53bc85..936daf7 100644 --- a/src/pages/api/users/[slug]/lessons/index.js +++ b/src/pages/api/users/[slug]/lessons/index.js @@ -1,11 +1,21 @@ import { getUserLessons, createOrUpdateUserLesson } from "@/db/models/userLessonModels"; import { getResourceById } from "@/db/models/resourceModels"; +import { getServerSession } from "next-auth/next" +import { authOptions } from "@/pages/api/auth/[...nextauth].js" // todo somehow make it to where we can get lesson slug in this endpoint export default async function handler(req, res) { const { method } = req; const { slug, courseId } = req.query; const userId = slug; + + const session = await getServerSession(req, res, authOptions); + + if (!session) { + res.status(401).json({ error: "Unauthorized" }); + return; + } + switch (method) { case "GET": try { diff --git a/src/pages/api/users/[slug]/lightning-address.js b/src/pages/api/users/[slug]/lightning-address.js index 1373cd5..8c55657 100644 --- a/src/pages/api/users/[slug]/lightning-address.js +++ b/src/pages/api/users/[slug]/lightning-address.js @@ -1,9 +1,18 @@ import { getLightningAddress, createLightningAddress, updateLightningAddress, deleteLightningAddress } from "@/db/models/lightningAddressModels" +import { getServerSession } from "next-auth/next" +import { authOptions } from "@/pages/api/auth/[...nextauth].js" export default async function handler(req, res) { const { slug } = req.query; const userId = slug; + const session = await getServerSession(req, res, authOptions); + + if (!session) { + res.status(401).json({ error: "Unauthorized" }); + return; + } + switch (req.method) { case 'GET': try { diff --git a/src/pages/api/users/[slug]/nip05.js b/src/pages/api/users/[slug]/nip05.js index f074f70..eaf60cf 100644 --- a/src/pages/api/users/[slug]/nip05.js +++ b/src/pages/api/users/[slug]/nip05.js @@ -1,9 +1,18 @@ import { getNip05, createNip05, updateNip05, deleteNip05 } from '@/db/models/nip05Models'; +import { getServerSession } from "next-auth/next" +import { authOptions } from "@/pages/api/auth/[...nextauth].js" export default async function handler(req, res) { const { slug } = req.query; const userId = slug; + const session = await getServerSession(req, res, authOptions); + + if (!session) { + res.status(401).json({ error: "Unauthorized" }); + return; + } + switch (req.method) { case 'GET': try { diff --git a/src/pages/api/users/index.js b/src/pages/api/users/index.js index ec1ad94..25db149 100644 --- a/src/pages/api/users/index.js +++ b/src/pages/api/users/index.js @@ -2,6 +2,7 @@ import { getAllUsers, createUser } from '@/db/models/userModels'; import { getServerSession } from "next-auth/next" import { authOptions } from "@/pages/api/auth/[...nextauth].js" +// todo add recaptcha for additional security export default async function handler(req, res) { // const session = await getServerSession(req, res, authOptions); if (req.method === 'POST') { diff --git a/src/pages/api/users/subscription/index.js b/src/pages/api/users/subscription/index.js index d5af83c..ad56ec0 100644 --- a/src/pages/api/users/subscription/index.js +++ b/src/pages/api/users/subscription/index.js @@ -1,6 +1,15 @@ import { updateUserSubscription } from "@/db/models/userModels"; +import { getServerSession } from "next-auth/next" +import { authOptions } from "@/pages/api/auth/[...nextauth].js" export default async function handler(req, res) { + const session = await getServerSession(req, res, authOptions); + + if (!session) { + res.status(401).json({ error: "Unauthorized" }); + return; + } + if (req.method === 'PUT') { try { const { userId, isSubscribed, nwc } = req.body;