mirror of
https://github.com/linux-odyssey/linux-odyssey.git
synced 2026-11-05 19:20:12 +08:00
feat: delete "deleteSession" method, validate questId and sessionId
This commit is contained in:
1 parent
a7422853fa
commit
5df4967a85
12 files changed
+67
-99
No files matched your search
@@ -45,15 +45,13 @@ async function setSession(session) {
|
||||
|
||||
export async function createSession() {
|
||||
console.log('Creating a new session...')
|
||||
const res = await api.post('/sessions', { quest_id: store.questId })
|
||||
const res = await api.post('/sessions', { questId: store.questId })
|
||||
const { data } = res
|
||||
await setSession(data)
|
||||
}
|
||||
|
||||
async function getActiveSession(questId) {
|
||||
const res = await api.post('/sessions/active', {
|
||||
quest_id: questId,
|
||||
})
|
||||
const res = await api.post('/sessions/active', { questId })
|
||||
const session = res.data
|
||||
try {
|
||||
await setSession(session)
|
||||
|
||||
@@ -12,7 +12,7 @@ class SocketWrapper {
|
||||
|
||||
this.socket = io('', {
|
||||
query: {
|
||||
session_id: session._id,
|
||||
sessionId: session._id,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -23,7 +23,7 @@ class SocketWrapper {
|
||||
this.socket.once('terminal', () => {
|
||||
resolve()
|
||||
})
|
||||
this.socket.once('error', reject)
|
||||
this.socket.once('connect_error', reject)
|
||||
this.bindListeners()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ function debug(...args) {
|
||||
async function createSession() {
|
||||
console.log('Creating a new session...')
|
||||
const res = await api.post('/sessions', {
|
||||
quest_id: 'helloworld',
|
||||
questId: 'helloworld',
|
||||
})
|
||||
const { data } = await res
|
||||
if (!data._id) {
|
||||
@@ -68,7 +68,7 @@ async function connect(sessionId, cookie) {
|
||||
Cookie: cookie,
|
||||
},
|
||||
query: {
|
||||
session_id: sessionId,
|
||||
sessionId,
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ export async function newCommand(req, res) {
|
||||
return
|
||||
}
|
||||
|
||||
const sessionId = req.user.session_id
|
||||
const { sessionId } = req.user
|
||||
|
||||
const session = await Session.findById(sessionId)
|
||||
|
||||
@@ -64,7 +64,7 @@ export async function newCommand(req, res) {
|
||||
}
|
||||
|
||||
export async function completedCommand(req, res) {
|
||||
const sessionId = req.user.session_id
|
||||
const { sessionId } = req.user
|
||||
|
||||
const session = await Session.findById(sessionId)
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Quest } from '@linux-odyssey/models'
|
||||
import { matchedData } from 'express-validator'
|
||||
|
||||
export async function getQuests(req, res) {
|
||||
const quests = await Quest.find({}).sort({ order: 1 })
|
||||
@@ -12,8 +13,8 @@ export async function getQuests(req, res) {
|
||||
}
|
||||
|
||||
export async function getQuestDetail(req, res) {
|
||||
const { id } = req.params
|
||||
const quest = await Quest.findById(id)
|
||||
const { questId } = matchedData(req)
|
||||
const quest = await Quest.findById(questId)
|
||||
if (!quest) {
|
||||
res.status(404).json({ message: 'Quest not found.' })
|
||||
return
|
||||
|
||||
@@ -28,10 +28,11 @@ function sessionDetail(session) {
|
||||
export async function getSessionList(req, res) {
|
||||
try {
|
||||
const query = { user: req.user._id }
|
||||
if (req.query.quest_id) {
|
||||
query.quest = req.query.quest_id
|
||||
const { questId, status } = matchedData(req)
|
||||
if (questId) {
|
||||
query.quest = questId
|
||||
}
|
||||
query.status = req.query.status || 'active'
|
||||
query.status = status || 'active'
|
||||
const sessions = await Session.find(query)
|
||||
res.json(sessions.map(sessionSummary))
|
||||
} catch (err) {
|
||||
@@ -41,9 +42,9 @@ export async function getSessionList(req, res) {
|
||||
}
|
||||
|
||||
export async function createSession(req, res) {
|
||||
const { quest_id } = matchedData(req)
|
||||
const { questId } = matchedData(req)
|
||||
try {
|
||||
const session = await createNewSession(req.user, quest_id)
|
||||
const session = await createNewSession(req.user, questId)
|
||||
res.status(201).json(sessionDetail(session))
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
@@ -53,8 +54,9 @@ export async function createSession(req, res) {
|
||||
|
||||
export async function getSessionById(req, res) {
|
||||
try {
|
||||
const { sessionId } = matchedData(req)
|
||||
const session = await Session.findOne({
|
||||
_id: req.params.id,
|
||||
_id: sessionId,
|
||||
user: req.user._id,
|
||||
})
|
||||
|
||||
@@ -69,28 +71,10 @@ export async function getSessionById(req, res) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteSessionById(req, res) {
|
||||
try {
|
||||
const session = await Session.findOneAndDelete({
|
||||
_id: req.params.id,
|
||||
user: req.user._id,
|
||||
})
|
||||
|
||||
if (!session) {
|
||||
res.status(404).json({ message: 'Session not found.' })
|
||||
return
|
||||
}
|
||||
|
||||
res.status(204).end()
|
||||
} catch (err) {
|
||||
res.status(500).json({ message: err.message })
|
||||
}
|
||||
}
|
||||
|
||||
export async function getOrCreateSession(req, res) {
|
||||
const { quest_id } = matchedData(req)
|
||||
const { questId } = matchedData(req)
|
||||
try {
|
||||
const session = await getOrCreateActiveSession(req.user, quest_id)
|
||||
const session = await getOrCreateActiveSession(req.user, questId)
|
||||
res.json(sessionDetail(session))
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Router } from 'express'
|
||||
import * as questController from '../controllers/questController.js'
|
||||
import { questIdValidator } from '../validators/questValidator.js'
|
||||
|
||||
const router = Router()
|
||||
|
||||
router.get('/', questController.getQuests)
|
||||
router.get('/:id', questController.getQuestDetail)
|
||||
router.get('/:questId', questIdValidator, questController.getQuestDetail)
|
||||
|
||||
export default router
|
||||
@@ -4,11 +4,13 @@ import { sessionRateLimit } from '../../middleware/rateLimiter.js'
|
||||
import {
|
||||
createSessionValidator,
|
||||
activeSessionValidator,
|
||||
sessionListValidator,
|
||||
sessionDetailValidator,
|
||||
} from '../validators/sessionValidator.js'
|
||||
|
||||
const router = Router()
|
||||
|
||||
router.get('/', sessionController.getSessionList)
|
||||
router.get('/', sessionListValidator, sessionController.getSessionList)
|
||||
router.post(
|
||||
'/',
|
||||
createSessionValidator,
|
||||
@@ -20,7 +22,6 @@ router.post(
|
||||
activeSessionValidator,
|
||||
sessionController.getOrCreateSession
|
||||
)
|
||||
router.get('/:id', sessionController.getSessionById)
|
||||
router.delete('/:id', sessionController.deleteSessionById)
|
||||
router.get('/:id', sessionDetailValidator, sessionController.getSessionById)
|
||||
|
||||
export default router
|
||||
+15
-17
@@ -1,8 +1,10 @@
|
||||
import { Server } from 'socket.io'
|
||||
import validator from 'validator'
|
||||
import { Session } from '@linux-odyssey/models'
|
||||
import { getAndStartContainer, attachContainer } from '../containers/docker.js'
|
||||
import SessionMiddleware from '../middleware/session.js'
|
||||
import { genJWT } from '../utils/auth.js'
|
||||
import { checkSessionId } from './validators/sessionValidator.js'
|
||||
|
||||
const sessions = new Map()
|
||||
|
||||
@@ -26,33 +28,26 @@ export function pushToSession(sessionId, event, ...args) {
|
||||
}
|
||||
}
|
||||
|
||||
async function connectClient(socket) {
|
||||
async function connectClient(socket, next) {
|
||||
const user = socket.request.session?.passport?.user
|
||||
if (!user) {
|
||||
socket.send('User not found.')
|
||||
socket.disconnect()
|
||||
next(new Error('User not found.'))
|
||||
return
|
||||
}
|
||||
const sessionId = socket.handshake.query.session_id
|
||||
if (!sessionId) {
|
||||
socket.emit('error', 'Session ID not found.')
|
||||
socket.disconnect()
|
||||
const { sessionId } = socket.handshake.query
|
||||
if (!validator.isMongoId(sessionId)) {
|
||||
next(new Error('Invalid Session ID.'))
|
||||
return
|
||||
}
|
||||
|
||||
const session = await Session.findOne({
|
||||
_id: sessionId,
|
||||
user,
|
||||
status: 'active',
|
||||
})
|
||||
const session = await Session.findById(sessionId)
|
||||
if (!session) {
|
||||
socket.emit('error', 'Session not found.')
|
||||
socket.disconnect()
|
||||
next(new Error('Session not found.'))
|
||||
return
|
||||
}
|
||||
|
||||
const token = await genJWT({
|
||||
session_id: session.id,
|
||||
sessionId: session.id,
|
||||
})
|
||||
|
||||
let container
|
||||
@@ -61,8 +56,7 @@ async function connectClient(socket) {
|
||||
container = await getAndStartContainer(session.containerId)
|
||||
stream = await attachContainer(container, { token })
|
||||
} catch (err) {
|
||||
socket.emit('error', 'Failed to start container.')
|
||||
socket.disconnect()
|
||||
next(new Error('Failed to start container.'))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -95,6 +89,10 @@ export default (server) => {
|
||||
const io = new Server(server)
|
||||
|
||||
io.engine.use(SessionMiddleware)
|
||||
io.engine.use(checkSessionId())
|
||||
|
||||
io.on('connection', connectClient)
|
||||
io.on('connect_error', (err) => {
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { check } from 'express-validator'
|
||||
import { noError } from '../../middleware/validator.js'
|
||||
|
||||
export const checkQuestId = () =>
|
||||
check('questId').notEmpty().isString().isAlphanumeric().isLength({ max: 64 })
|
||||
|
||||
export const questIdValidator = [checkQuestId(), noError]
|
||||
|
||||
export default {
|
||||
questIdValidator,
|
||||
}
|
||||
@@ -1,8 +1,20 @@
|
||||
import { check } from 'express-validator'
|
||||
import { checkQuestId } from './questValidator.js'
|
||||
import { noError } from '../../middleware/validator.js'
|
||||
|
||||
const checkQuestId = () =>
|
||||
check('quest_id').notEmpty().isString().isLowercase().isLength({ max: 64 })
|
||||
const checkSessionStatus = () =>
|
||||
check('status')
|
||||
.isString()
|
||||
.custom((value) => ['active', 'inactive', 'finished'].includes(value))
|
||||
|
||||
export const checkSessionId = () =>
|
||||
check('sessionId').notEmpty().isString().isMongoId()
|
||||
|
||||
export const sessionListValidator = [
|
||||
checkQuestId(),
|
||||
checkSessionStatus(),
|
||||
noError,
|
||||
]
|
||||
export const sessionDetailValidator = [checkSessionId(), noError]
|
||||
export const createSessionValidator = [checkQuestId(), noError]
|
||||
export const activeSessionValidator = [checkQuestId(), noError]
|
||||
@@ -143,44 +143,6 @@ paths:
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
delete:
|
||||
tags:
|
||||
- signed-in
|
||||
summary: delete a specific session by ID
|
||||
security:
|
||||
- cookieAuth: []
|
||||
parameters:
|
||||
- in: path
|
||||
name: sessionId
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: objectId
|
||||
example: 64b7a3a3c182b4826dd1aaa1
|
||||
responses:
|
||||
'204':
|
||||
description: Session successfully deleted
|
||||
|
||||
'404':
|
||||
description: Session not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
example: 'Session not found.'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
example: 'Unauthorized.'
|
||||
|
||||
/auth/register:
|
||||
post:
|
||||
|
||||
Reference in new issue
Block a user