Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
tktcorporation committed Oct 10, 2022
1 parent 068cc74 commit 2d238d6
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "User" ADD COLUMN "roles" TEXT NOT NULL DEFAULT 'moderator';
1 change: 1 addition & 0 deletions api/db/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ model User {
salt String
resetToken String?
resetTokenExpiresAt DateTime?
roles String @default("moderator")
}

model Comment {
Expand Down
38 changes: 22 additions & 16 deletions api/src/lib/auth.js → api/src/lib/auth.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { Decoded } from '@redwoodjs/api'
import { AuthenticationError, ForbiddenError } from '@redwoodjs/graphql-server'

import { db } from './db'
Expand All @@ -19,10 +20,14 @@ import { db } from './db'
* fields to the `select` object below once you've decided they are safe to be
* seen if someone were to open the Web Inspector in their browser.
*/
export const getCurrentUser = async (session) => {
export const getCurrentUser = async (session: Decoded) => {
if (!session || typeof session.id !== 'number') {
throw new Error('Invalid session')
}

return await db.user.findUnique({
where: { id: session.id },
select: { id: true, email: true },
select: { id: true, email: true, roles: true },
})
}

Expand All @@ -31,19 +36,25 @@ export const getCurrentUser = async (session) => {
*
* @returns {boolean} - If the currentUser is authenticated
*/
export const isAuthenticated = () => {
export const isAuthenticated = (): boolean => {
return !!context.currentUser
}

/**
* When checking role membership, roles can be a single value, a list, or none.
* You can use Prisma enums too (if you're using them for roles), just import your enum type from `@prisma/client`
*/
type AllowedRoles = string | string[] | undefined

/**
* Checks if the currentUser is authenticated (and assigned one of the given roles)
*
* @param roles: AllowedRoles - Checks if the currentUser is assigned one of these roles
* @param roles: {@link AllowedRoles} - Checks if the currentUser is assigned one of these roles
*
* @returns {boolean} - Returns true if the currentUser is logged in and assigned one of the given roles,
* or when no roles are provided to check against. Otherwise returns false.
*/
export const hasRole = (roles) => {
export const hasRole = (roles: AllowedRoles): boolean => {
if (!isAuthenticated()) {
return false
}
Expand All @@ -54,9 +65,6 @@ export const hasRole = (roles) => {
if (typeof currentUserRoles === 'string') {
// roles to check is a string, currentUser.roles is a string
return currentUserRoles === roles
} else if (Array.isArray(currentUserRoles)) {
// roles to check is a string, currentUser.roles is an array
return currentUserRoles?.some((allowedRole) => roles === allowedRole)
}
}

Expand All @@ -66,11 +74,9 @@ export const hasRole = (roles) => {
return currentUserRoles?.some((allowedRole) =>
roles.includes(allowedRole)
)
} else if (typeof context.currentUser.roles === 'string') {
} else if (typeof currentUserRoles === 'string') {
// roles to check is an array, currentUser.roles is a string
return roles.some(
(allowedRole) => context.currentUser?.roles === allowedRole
)
return roles.some((allowedRole) => currentUserRoles === allowedRole)
}
}

Expand All @@ -83,16 +89,16 @@ export const hasRole = (roles) => {
* whether or not they are assigned a role, and optionally raise an
* error if they're not.
*
* @param roles: AllowedRoles - When checking role membership, these roles grant access.
* @param roles: {@link AllowedRoles} - When checking role membership, these roles grant access.
*
* @returns - If the currentUser is authenticated (and assigned one of the given roles)
*
* @throws {AuthenticationError} - If the currentUser is not authenticated
* @throws {ForbiddenError} If the currentUser is not allowed due to role permissions
* @throws {@link AuthenticationError} - If the currentUser is not authenticated
* @throws {@link ForbiddenError} If the currentUser is not allowed due to role permissions
*
* @see https://github.com/redwoodjs/redwood/tree/main/packages/auth for examples
*/
export const requireAuth = ({ roles }) => {
export const requireAuth = ({ roles }: { roles?: AllowedRoles } = {}) => {
if (!isAuthenticated()) {
throw new AuthenticationError("You don't have permission to do that.")
}
Expand Down

0 comments on commit 2d238d6

Please sign in to comment.