From f6964c0f786fae9b988356fc153eb6251d796af3 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sat, 7 Nov 2020 21:44:12 +1100 Subject: [PATCH] Add auth into who can edit a part --- api/src/lib/owner.js | 38 ++++++++++++------- api/src/services/parts/parts.js | 8 +++- web/src/components/PartProfile/PartProfile.js | 11 +++++- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/api/src/lib/owner.js b/api/src/lib/owner.js index 7bb0046..e52ac90 100644 --- a/api/src/lib/owner.js +++ b/api/src/lib/owner.js @@ -1,31 +1,43 @@ import { AuthenticationError, ForbiddenError, parseJWT } from '@redwoodjs/api' import { db } from 'src/lib/db' -export const requireOwnership = async ({ id, userName } = {}) => { +export const requireOwnership = async ({ userId, userName, partId } = {}) => { + // IMPORTANT, don't forget to await this function, as it will only block + // unwanted db actions if it has time to look up resources in the db. if (!context.currentUser) { throw new AuthenticationError("You don't have permission to do that.") } - if(!id && !userName) { + if(!userId && !userName && !partId) { throw new ForbiddenError("You don't have access to do that.") } - const netlifyUserId = context.currentUser?.sub - if(id && id !== netlifyUserId) { - throw new ForbiddenError("You don't own this resource.") - } - if(context.currentUser.roles?.includes('admin')) { return } - const user = await db.user.findOne({ - where: { userName }, - }) - - console.log(user, 'USER') - if(!user) { + const netlifyUserId = context.currentUser?.sub + if(userId && userId !== netlifyUserId) { throw new ForbiddenError("You don't own this resource.") } + if(userName) { + const user = await db.user.findOne({ + where: { userName }, + }) + + if(!user || user.id !== netlifyUserId) { + throw new ForbiddenError("You don't own this resource.") + } + } + + if(partId) { + const user = await db.part.findOne({ + where: { id: partId }, + }).user() + + if(!user || user.id !== netlifyUserId) { + throw new ForbiddenError("You don't own this resource.") + } + } } diff --git a/api/src/services/parts/parts.js b/api/src/services/parts/parts.js index 2460149..8589c5e 100644 --- a/api/src/services/parts/parts.js +++ b/api/src/services/parts/parts.js @@ -1,5 +1,7 @@ import { db } from 'src/lib/db' import { foreignKeyReplacement } from 'src/services/helpers' +import { requireAuth } from 'src/lib/auth' +import { requireOwnership } from 'src/lib/owner' import { user } from 'src/services/users/users' export const parts = () => { @@ -28,12 +30,15 @@ export const partByUserAndTitle = async ({ userName, partTitle }) => { } export const createPart = async ({ input }) => { + requireAuth() return db.part.create({ data: foreignKeyReplacement(input), }) } -export const updatePart = ({ id, input }) => { +export const updatePart = async ({ id, input }) => { + requireAuth() + await requireOwnership({partId: id}) return db.part.update({ data: foreignKeyReplacement(input), where: { id }, @@ -41,6 +46,7 @@ export const updatePart = ({ id, input }) => { } export const deletePart = ({ id }) => { + requireAuth() return db.part.delete({ where: { id }, }) diff --git a/web/src/components/PartProfile/PartProfile.js b/web/src/components/PartProfile/PartProfile.js index 8806ba5..2f87759 100644 --- a/web/src/components/PartProfile/PartProfile.js +++ b/web/src/components/PartProfile/PartProfile.js @@ -1,6 +1,7 @@ import {useState, useEffect} from 'react' -import Editor from "rich-markdown-editor"; +import { useAuth } from '@redwoodjs/auth' import { navigate, routes } from '@redwoodjs/router' +import Editor from "rich-markdown-editor"; import ImageUploader from 'src/components/ImageUploader' import Breadcrumb from 'src/components/Breadcrumb' @@ -8,7 +9,13 @@ import EmojiReaction from 'src/components/EmojiReaction' import Button from 'src/components/Button' const PartProfile = ({userPart, isEditable, onSave, loading, error}) => { + const { currentUser } = useAuth() + const canEdit = currentUser?.sub === userPart.id const part = userPart?.Part + useEffect(() => {isEditable && + !canEdit && + navigate(routes.part2({userName: userPart.userName, partTitle: part.title}))}, + [currentUser]) const [input, setInput] = useState({ title: part.title, mainImage: part.mainImage, @@ -65,7 +72,7 @@ const PartProfile = ({userPart, isEditable, onSave, loading, error}) => { > Open IDE - {true &&