From 0f53696f714786d722dfbf23b748c6fa840ff91f Mon Sep 17 00:00:00 2001 From: wancat Date: Tue, 12 Sep 2023 00:12:09 +0800 Subject: [PATCH] feat: apply auth to container and cli client --- packages/client/index.js | 43 +++++++++++++++++-- packages/container/cli.js | 2 +- .../src/api/controllers/commandController.js | 12 +----- .../src/api/controllers/sessionController.js | 6 +-- server/src/api/routes/auth.js | 4 +- server/src/api/socket.js | 14 ++++-- server/src/utils/auth.js | 2 +- server/swagger.yaml | 8 ++-- 8 files changed, 64 insertions(+), 27 deletions(-) diff --git a/packages/client/index.js b/packages/client/index.js index 99ec410..2fb574a 100644 --- a/packages/client/index.js +++ b/packages/client/index.js @@ -57,21 +57,29 @@ async function lastSession() { return session } -async function connect(sessionId) { +async function connect(sessionId, token) { console.log(`Session ID: ${sessionId}`) console.log('Use Ctrl + D to exit.') if (!sessionId) exit() const socket = io(program.opts().host, { + auth: { + token, + }, query: { session_id: sessionId, }, }) - socket.on('open', function open() { + socket.on('connection', function open() { console.log('Connected to the server.') }) + socket.on('connect_error', (err) => { + console.error(err.message) + exit(1) + }) + socket.on('message', console.log) socket.on('terminal', function incoming(data) { @@ -101,6 +109,26 @@ async function connect(sessionId) { }) } +async function login() { + try { + const res = await api.post('/login/password', { + username: program.opts().user, + password: program.opts().password, + }) + const { token } = res.data + if (!token) { + console.error(res.data) + exit(1) + } + console.log('Login success.') + return token + } catch (err) { + console.error(err.message) + exit(1) + return null + } +} + async function main() { api = axios.create({ baseURL: `${program.opts().host}/api/v1`, @@ -111,18 +139,27 @@ async function main() { console.log(program.opts().session) // main() + const token = await login() + api.defaults.headers.common.Authorization = `Bearer ${token}` + const sessionId = program.opts().session || (program.opts().create ? (await createSession())._id : null) || (await lastSession())._id - await connect(sessionId) + await connect(sessionId, token) } program .option('-s, --session ', 'Session ID') .option('-c, --create', 'Create a new session') .option('-d, --debug', 'Debug mode') + .option('-u, --user ', 'Username', get('USERNAME', 'testUser')) + .option( + '-p, --password ', + 'Password', + get('PASSWORD', 'testPassword') + ) .option( '-h, --host ', 'Server host', diff --git a/packages/container/cli.js b/packages/container/cli.js index fac7eba..a6f71d3 100644 --- a/packages/container/cli.js +++ b/packages/container/cli.js @@ -49,7 +49,6 @@ async function main() { output, error, exit_code: CMD_EXIT_CODE, - token: TOKEN, pwd: PWD, ...additionalData, } @@ -58,6 +57,7 @@ async function main() { method: 'POST', headers: { 'Content-Type': 'application/json', + Authorization: `Bearer ${TOKEN}`, }, body: JSON.stringify(payload), }) diff --git a/server/src/api/controllers/commandController.js b/server/src/api/controllers/commandController.js index fd583e1..5b3465c 100644 --- a/server/src/api/controllers/commandController.js +++ b/server/src/api/controllers/commandController.js @@ -1,26 +1,18 @@ /* eslint-disable import/prefer-default-export */ import Command from '../../models/command.js' import Session from '../../models/session.js' -import { verifySessionJWT } from '../../utils/auth.js' import CommandHandler from '../../game/commandHandler.js' export async function newCommand(req, res) { console.log('new command:', req.body) - const { token, command, pwd, output, error, ...additionalData } = req.body + const { command, pwd, output, error, ...additionalData } = req.body if (!command) { res.status(400).json({ message: 'command is required' }) return } - let sessionId - try { - const decoded = await verifySessionJWT(token) - sessionId = decoded.session_id - } catch (err) { - res.status(401).json({ message: 'token not valid' }) - return - } + const sessionId = req.user.session_id const session = await Session.findById(sessionId) diff --git a/server/src/api/controllers/sessionController.js b/server/src/api/controllers/sessionController.js index 3130288..656d12f 100644 --- a/server/src/api/controllers/sessionController.js +++ b/server/src/api/controllers/sessionController.js @@ -5,7 +5,7 @@ import SessionHandler from '../../game/sessionHandler.js' export async function getSessionList(req, res) { try { - const query = { user: req.user.id } + const query = { user: req.user._id } if (req.query.quest_id) { query.quest = req.query.quest_id } @@ -70,7 +70,7 @@ export async function getSessionById(req, res) { try { const session = await Session.findOne({ _id: req.params.id, - user: req.user.id, + user: req.user._id, }) if (!session) { @@ -88,7 +88,7 @@ export async function deleteSessionById(req, res) { try { const session = await Session.findOneAndDelete({ _id: req.params.id, - user: req.user.id, + user: req.user._id, }) if (!session) { diff --git a/server/src/api/routes/auth.js b/server/src/api/routes/auth.js index 8d7afdd..54bcc74 100644 --- a/server/src/api/routes/auth.js +++ b/server/src/api/routes/auth.js @@ -1,13 +1,13 @@ import { Router } from 'express' import passport from 'passport' -import { genJwt } from '../../utils/auth.js' +import { genJWT } from '../../utils/auth.js' const router = Router() async function issueToken(req, res) { const { user } = req - const token = await genJwt({ + const token = await genJWT({ _id: user.id, username: user.username, email: user.email, diff --git a/server/src/api/socket.js b/server/src/api/socket.js index 67b9d77..1188a1c 100644 --- a/server/src/api/socket.js +++ b/server/src/api/socket.js @@ -1,7 +1,7 @@ import { Server } from 'socket.io' import { getAndStartContainer, attachContainer } from '../containers/docker.js' import Session from '../models/session.js' -import { defaultUser, genSessionJWT } from '../utils/auth.js' +import { genJWT, verifyJWT } from '../utils/auth.js' const sessions = new Map() @@ -45,7 +45,9 @@ async function connectClient(socket) { return } - const token = await genSessionJWT(session) + const token = await genJWT({ + session_id: session.id, + }) let container let stream @@ -90,8 +92,14 @@ export default (server) => { io.use(async (socket, next) => { console.log('Authenticating...') try { - const user = await defaultUser() + const { token } = socket.handshake.auth + if (!token) { + next(new Error('Token not found.')) + return + } + const user = await verifyJWT(token) // eslint-disable-next-line no-param-reassign + console.log(user) socket.user = user next() } catch (err) { diff --git a/server/src/utils/auth.js b/server/src/utils/auth.js index 6388cf6..cc8c97d 100644 --- a/server/src/utils/auth.js +++ b/server/src/utils/auth.js @@ -27,7 +27,7 @@ export async function defaultUser() { return user } -export function genJwt(payload) { +export function genJWT(payload) { return new Promise((resolve, reject) => { jwt.sign( payload, diff --git a/server/swagger.yaml b/server/swagger.yaml index c895628..9f3dfe6 100644 --- a/server/swagger.yaml +++ b/server/swagger.yaml @@ -303,6 +303,10 @@ paths: /commands: post: summary: Record a command that was executed in a session + tags: + - signed-in + security: + - BearerAuth: [] requestBody: required: true content: @@ -433,13 +437,9 @@ components: Command: type: object required: - - token - pwd - command properties: - token: - type: string - description: The JWT token of the session pwd: type: string example: '/root'