Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mitigate the issue of creating a submission based on the cliToken ID #1553

Merged
merged 15 commits into from
Mar 9, 2022
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions @types/user.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@ export type UserInfo = {
discordUsername: string
discordAvatarUrl: string
}

export type CliToken = {
id: number
cliToken: string
}
32 changes: 29 additions & 3 deletions helpers/controllers/submissionController.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
jest.mock('../discordBot.ts')
jest.mock('../hasPassedLesson')
jest.mock('../updateSubmission')
jest.mock('@sentry/node')
import { SubmissionStatus } from '../../graphql'
import prismaMock from '../../__tests__/utils/prismaMock'
import { hasPassedLesson } from '../hasPassedLesson'
Expand All @@ -16,6 +17,7 @@ import {
rejectSubmission,
submissions
} from './submissionController'
import * as Sentry from '@sentry/node'

describe('Submissions Mutations', () => {
hasPassedLesson.mockResolvedValue(true)
Expand Down Expand Up @@ -43,6 +45,7 @@ describe('Submissions Mutations', () => {
diff: 'fakeDiff',
lessonId: 1
}
const ctx = { req: { user: { id: 2 } } }

beforeEach(() => {
prismaMock.submission.create.mockResolvedValue({
Expand All @@ -53,7 +56,7 @@ describe('Submissions Mutations', () => {
})

test('should save and return submission', async () => {
await expect(createSubmission(null, args)).resolves.toEqual({
await expect(createSubmission(null, args, ctx)).resolves.toEqual({
id: 1,
diff: 'fakeDiff',
lesson: {
Expand All @@ -68,15 +71,38 @@ describe('Submissions Mutations', () => {

test('should overwrite previous submission status if it exists', async () => {
prismaMock.submission.findFirst.mockResolvedValue({ id: 1 })
await createSubmission(null, args)
await createSubmission(null, args, ctx)
expect(prismaMock.submission.update).toBeCalled()
})

test('should throw error Invalid args', () => {
return expect(createSubmission(null, null)).rejects.toThrow(
return expect(createSubmission(null, null, ctx)).rejects.toThrow(
'Invalid args'
)
})

test('should set id to the decoded clientToken id when req.user is undefined', async () => {
await createSubmission(null, args, { ...ctx, req: { user: null } })
expect(prismaMock.submission.findFirst).toBeCalledWith({
where: {
challengeId: args.challengeId,
lessonId: args.lessonId,
user: { id: 1210 },
status: SubmissionStatus.Open
}
})
})

test('should send message to Sentry if req.user does not exist and cliToken does', async () => {
prismaMock.user.findFirst.mockResolvedValue({
id: 1210,
username: 'noob'
})
await createSubmission(null, args, { ...ctx, req: { user: null } })
expect(Sentry.captureException).toHaveBeenCalledWith({
message: `${1210}/${'noob'} is using the wrong CLI version. Must be 2.2.5`
})
})
})

describe('acceptSubmission', () => {
Expand Down
24 changes: 21 additions & 3 deletions helpers/controllers/submissionController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,36 @@ import {
SubmissionStatus
} from '../../graphql'
import prisma from '../../prisma'
import { decode } from '../encoding'
import { hasPassedLesson } from '../hasPassedLesson'
import { updateSubmission } from '../updateSubmission'
import { sendSubmissionNotification, IdType } from '../discordBot'
import { decode } from '../encoding'
import * as Sentry from '@sentry/node'
import { CliToken } from '../../@types/user'

export const createSubmission = async (
_parent: void,
args: MutationCreateSubmissionArgs
args: MutationCreateSubmissionArgs,
ctx: Context
): Promise<CreateSubmissionMutation['createSubmission']> => {
const { req } = ctx

if (!args) throw new Error('Invalid args')
const { challengeId, cliToken, diff, lessonId } = args
const { id } = decode(cliToken)

const decodedCliToken: CliToken = cliToken && decode(cliToken)
flacial marked this conversation as resolved.
Show resolved Hide resolved
const id = !req.user || !req.user.id ? decodedCliToken.id : req.user.id
flacial marked this conversation as resolved.
Show resolved Hide resolved

if (!req.user && cliToken) {
const user = await prisma.user.findFirst({
where: { cliToken: decodedCliToken.cliToken }
})

Sentry.captureException({
message: `${user?.id}/${user?.username} is using the wrong CLI version. Must be 2.2.5`
})
}

const previousSubmission = await prisma.submission.findFirst({
where: {
challengeId,
Expand Down
30 changes: 27 additions & 3 deletions helpers/middleware/user.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const mockUserInfo = {
password: '$2b$10$W9KwQ6Sbi0RJjD2GZYX9BugAtgSm/W999gNW1f/XiRcI6NiC9pTdK',
email: '[email protected]',
isAdmin: false,
cliToken: 'KfizzIlWp111fizzDbuzzr'
cliToken: 'W29iamVjdCBPYmplY3Rd'
}

const res = {}
Expand All @@ -26,15 +26,39 @@ const next = () => {}
describe('User Middleware', () => {
beforeEach(() => {
prismaMock.user.findUnique.mockResolvedValue(mockUserInfo)
prismaMock.user.findFirst.mockResolvedValue(mockUserInfo)
})
test('Should return null when userId property of req.session is not there', async () => {
const req = { session: '' }
const req = {
session: '',
headers: {
authorization: null
}
}
await userMiddleware(req, res, next)
expect(req.user).toBeNull
})

test('Should return correct info from database if session.userId exists', async () => {
const req = { session: { userId: 'noob' } }
const req = {
session: {
userId: 'noob'
},
headers: {
authorization: null
}
}
await userMiddleware(req, res, next)
expect(req.user).toEqual(mockUserInfo)
})
test('Should return correct info from database if authorization header exists', async () => {
const req = {
session: { userId: 'noob' },
headers: {
authorization:
'Bearer eyJpZCI6MSwiY2xpVG9rZW4iOiJXMjlpYW1WamRDQlBZbXBsWTNSZCJ9'
}
}
await userMiddleware(req, res, next)
expect(req.user).toEqual(mockUserInfo)
})
Expand Down
20 changes: 19 additions & 1 deletion helpers/middleware/user.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,29 @@
import { LoggedRequest } from '../../@types/helpers'
import { NextApiResponse } from 'next'
import prisma from '../../prisma'
import { decode } from '../encoding'
import { CliToken } from '../../@types/user'

export default async (
const userMiddleware = async (
req: LoggedRequest,
_: NextApiResponse,
next: () => void
) => {
req.user = null

const auth = req.headers.authorization
const cliToken = auth && auth.split(' ')[1]
if (cliToken) {
const decodedCliToken: CliToken = decode(cliToken)

const user = await prisma.user.findFirst({
where: { cliToken: decodedCliToken.cliToken }
})

req.user = user
return next()
}

const { session } = req
if (session?.userId) {
const { userId: id } = session
Expand All @@ -16,3 +32,5 @@ export default async (
}
next()
}

export default userMiddleware