Skip to content

Commit

Permalink
Merge pull request #128 from redpwn/fix/client-state-desync
Browse files Browse the repository at this point in the history
Fix client state desync
  • Loading branch information
chen-robert committed Mar 26, 2020
2 parents 5992572 + f4e2151 commit 438b6ad
Show file tree
Hide file tree
Showing 12 changed files with 73 additions and 54 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"watch:ts": "tsc -w",
"dev": "yarn build:ts && concurrently -k -t \"HH:mm:ss.SSS\" -p \"[{time}]\" -c \"cyan,green,red\" \"yarn:watch:*\"",
"test": "yarn build && nyc --skip-full ava",
"test:slim": "ava",
"test:report": "nyc --skip-full --reporter=lcov ava",
"commit": "git cz",
"copy-static": "sh -c \"cpy 'server/**/*' '.rdeploy' '!**/*.ts' dist/ --no-overwrite --parents\""
Expand Down
15 changes: 12 additions & 3 deletions server/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const express = require('express')
const Ajv = require('ajv')
const { responses, responseList } = require('../responses')
const auth = require('../auth')
const db = require('../database')

const router = express.Router()

Expand Down Expand Up @@ -62,18 +63,26 @@ routes.forEach((route, i) => {
}
}

let uuid
let user
if (route.requireAuth) {
const authHeader = req.get('authorization')
if (authHeader === undefined || !authHeader.startsWith('Bearer ')) {
sendResponse(responses.badToken)
return
}
uuid = await auth.token.getData(auth.token.tokenKinds.auth, authHeader.slice('Bearer '.length))
const uuid = await auth.token.getData(auth.token.tokenKinds.auth, authHeader.slice('Bearer '.length))
if (uuid === null) {
sendResponse(responses.badToken)
return
}

user = await db.auth.getUserById({
id: uuid
})
if (user == null) {
sendResponse(responses.badToken)
return
}
}

const validator = routeValidators[i]
Expand All @@ -93,7 +102,7 @@ routes.forEach((route, i) => {
try {
response = await route.handler({
req,
uuid
user
})
} catch (e) {
sendResponse(responses.errorInternal)
Expand Down
4 changes: 3 additions & 1 deletion server/api/submitflag.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ module.exports = {
required: ['id']
}
},
handler: async ({ req, uuid }) => {
handler: async ({ req, user }) => {
const uuid = user.id

if (Date.now() < config.startTime) {
return util.notStarted()
}
Expand Down
3 changes: 2 additions & 1 deletion server/api/users/delete.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ module.exports = {
method: 'delete',
path: '/users/me',
requireAuth: true,
handler: async ({ uuid }) => {
handler: async ({ user }) => {
const uuid = user.id
await database.auth.removeUserById({
id: uuid
})
Expand Down
1 change: 0 additions & 1 deletion server/api/users/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
module.exports = [
require('./me'),
require('./id'),
require('./me-solves'),
require('./delete'),
require('./update')
]
17 changes: 0 additions & 17 deletions server/api/users/me-solves.js

This file was deleted.

5 changes: 2 additions & 3 deletions server/api/users/me.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ module.exports = {
method: 'get',
path: '/users/me',
requireAuth: true,
handler: async ({ uuid }) => {
handler: async ({ user }) => {
const uuid = user.id
const userData = await getGenericUserData({
id: uuid
})

if (userData === null) return responses.badUnknownUser

const teamToken = await auth.token.getToken(auth.token.tokenKinds.team, uuid)

return [responses.goodUserData, {
Expand Down
11 changes: 6 additions & 5 deletions server/api/users/update.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ module.exports = {
}
}
},
handler: async ({ uuid, req }) => {
handler: async ({ user, req }) => {
const uuid = user.id
const { name, division } = req.body

const passRateLimit = await timeouts.checkRateLimit({
Expand All @@ -37,17 +38,17 @@ module.exports = {
}]
}

const user = await database.auth.updateUser({
const newUser = await database.auth.updateUser({
id: uuid,
name,
division
})

return [responses.goodUserUpdate, {
user: {
name: user.name,
email: user.email,
division: Number.parseInt(user.division)
name: newUser.name,
email: newUser.email,
division: Number.parseInt(newUser.division)
}
}]
}
Expand Down
24 changes: 22 additions & 2 deletions test/_util.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,31 @@ require('ava')

const { v4: uuidv4 } = require('uuid')
const config = require('../config/server')
const db = require('../dist/server/database')

module.exports = {
const ret = {
// Generate only valid parameters
generateTestUser: () => {
return {
email: uuidv4() + '@test.com',
name: uuidv4(),
division: Object.values(config.divisions)[0]
division: Object.values(config.divisions)[0],
perms: 0
}
},
// Generate a real user, adding to database
generateRealTestUser: async () => {
const id = uuidv4()

const userData = ret.generateTestUser()
const user = await db.auth.makeUser({
...userData,
id
})

return {
user,
cleanup: () => db.auth.removeUserById({ id })
}
},
getFirstLoadedChallenge: () => {
Expand Down Expand Up @@ -38,3 +56,5 @@ module.exports = {
})
}
}

module.exports = ret
15 changes: 12 additions & 3 deletions test/integration/challenges.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
const test = require('ava')
const request = require('supertest')
const app = require('../../dist/server/app')
const { v4: uuidv4 } = require('uuid')
const util = require('../_util')
const auth = require('../../dist/server/auth')
const config = require('../../dist/config/server')

const { responseList } = require('../../dist/server/responses')

let uuid, testUserData

test.before(async () => {
testUserData = await util.generateRealTestUser()
uuid = testUserData.user.id
})

test.after.always('cleanup test user', async t => {
await testUserData.cleanup()
})

test('fails with unauthorized', async t => {
const resp = await request(app)
.get(process.env.API_ENDPOINT + '/challs')
Expand All @@ -15,8 +26,6 @@ test('fails with unauthorized', async t => {
t.is(resp.body.kind, 'badToken')
})

const uuid = uuidv4()

test.serial('fails with badNotStarted', async t => {
const oldTime = config.startTime
// Choose a time 10 minutes in the future
Expand Down
20 changes: 6 additions & 14 deletions test/integration/submit.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,19 @@ const { responseList } = require('../../dist/server/responses')
const auth = require('../../dist/server/auth')
const util = require('../_util')

let chall
let chall, uuid, testUserData

// Wait for challenges to load
test.before(async () => {
chall = await util.getFirstLoadedChallenge()

testUserData = await util.generateRealTestUser()
uuid = testUserData.user.id
})

test.after.always('remove solves from test user', async t => {
test.after.always('cleanup test user', async t => {
await db.solves.removeSolvesByUserId({ userid: uuid })
await db.auth.removeUserById({
id: testUser.id
})
await testUserData.cleanup()
})

test('fails with unauthorized', async t => {
Expand All @@ -30,13 +31,6 @@ test('fails with unauthorized', async t => {
t.is(resp.body.kind, 'badToken')
})

const uuid = uuidv4()
const testUser = {
...util.generateTestUser(),
id: uuid,
perms: 0
}

test('fails with badBody', async t => {
const badChallenge = uuidv4()

Expand All @@ -61,8 +55,6 @@ test.serial('fails with badFlag', async t => {
})

test.serial('succeeds with goodFlag', async t => {
await db.auth.makeUser(testUser)

const authToken = await auth.token.getToken(auth.token.tokenKinds.auth, uuid)
const resp = await request(app)
.post(process.env.API_ENDPOINT + '/challs/' + encodeURIComponent(chall.id) + '/submit')
Expand Down
11 changes: 7 additions & 4 deletions test/integration/submitTiming.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,23 @@ const test = require('ava')
const request = require('supertest')
const app = require('../../dist/server/app')
const config = require('../../dist/config/server')
const { v4: uuidv4 } = require('uuid')
const util = require('../_util')

const { responseList } = require('../../dist/server/responses')
const auth = require('../../dist/server/auth')
const { getFirstLoadedChallenge } = require('../_util.js')

let chall
let chall, uuid, testUserData

// Wait for challenges to load
test.before(async () => {
chall = await getFirstLoadedChallenge()
testUserData = await util.generateRealTestUser()
uuid = testUserData.user.id
})

const uuid = uuidv4()
test.after.always('cleanup test user', async t => {
await testUserData.cleanup()
})

test.serial('fails with badNotStarted', async t => {
const oldTime = config.startTime
Expand Down

0 comments on commit 438b6ad

Please sign in to comment.