From 77016056eb95a5e4fd35f143c3c35cc3b808517a Mon Sep 17 00:00:00 2001 From: Kacper Michalik Date: Wed, 11 Oct 2023 10:13:33 +0200 Subject: [PATCH] generate random secret --- packages/backend/src/backendManager.ts | 4 ++-- packages/backend/src/nest/app.module.ts | 14 +++++++++----- packages/backend/src/nest/types.ts | 2 +- packages/common/src/jwt.ts | 11 ++++++----- packages/desktop/src/main/main.ts | 10 +++++----- packages/desktop/src/renderer/sagas/index.saga.ts | 4 ++-- .../src/renderer/sagas/socket/socket.saga.ts | 9 +++++---- .../src/renderer/sagas/socket/socket.slice.ts | 2 +- .../desktop/src/renderer/testUtils/prepareStore.ts | 2 +- 9 files changed, 32 insertions(+), 26 deletions(-) diff --git a/packages/backend/src/backendManager.ts b/packages/backend/src/backendManager.ts index f5a6d4884a..82f998af2a 100644 --- a/packages/backend/src/backendManager.ts +++ b/packages/backend/src/backendManager.ts @@ -24,7 +24,7 @@ program .option('-a, --appDataPath ', 'Path of application data directory') .option('-d, --socketIOPort ', 'Socket io data server port') .option('-r, --resourcesPath ', 'Application resources path') - .option('-tkn, --socketIOToken ', 'socketIO token') + .option('-scrt, --socketIOSecret ', 'socketIO secret') program.parse(process.argv) const options = program.opts() @@ -53,7 +53,7 @@ export const runBackendDesktop = async () => { const app = await NestFactory.createApplicationContext( AppModule.forOptions({ socketIOPort: options.socketIOPort, - socketIOToken: options.socketIOToken, + socketIOSecret: options.socketIOSecret, torBinaryPath: torBinForPlatform(resourcesPath), torResourcesPath: torDirForPlatform(resourcesPath), torControlPort: await getPort(), diff --git a/packages/backend/src/nest/app.module.ts b/packages/backend/src/nest/app.module.ts index 91e7a75722..bcee10daaf 100644 --- a/packages/backend/src/nest/app.module.ts +++ b/packages/backend/src/nest/app.module.ts @@ -106,8 +106,7 @@ export class AppModule { const authToken = req.headers['authorization'] if (!authToken) { console.error('No authorization header') - - res.writeHead(401, 'Unauthorized') + res.writeHead(401, 'No authorization header') res.end() return } @@ -115,17 +114,22 @@ export class AppModule { const socketIOToken = authToken && authToken.split(' ')[1] if (!socketIOToken) { console.error('No auth token') + res.writeHead(401, 'No authorization token') + res.end() + return + } - res.writeHead(401, 'Unauthorized') + if (!options.socketIOSecret) { + console.error('No socketIoSecret') + res.writeHead(401, 'No socketIoSecret') res.end() return } - if (verifyJWT(socketIOToken)) { + if (verifyJWT(socketIOToken, options.socketIOSecret)) { next() } else { console.error('Wrong JWT') - res.writeHead(401, 'Unauthorized') res.end() } diff --git a/packages/backend/src/nest/types.ts b/packages/backend/src/nest/types.ts index d5418f2cfa..8639d15944 100644 --- a/packages/backend/src/nest/types.ts +++ b/packages/backend/src/nest/types.ts @@ -5,7 +5,7 @@ import { Server as SocketIO } from 'socket.io' export class ConnectionsManagerTypes { options: Partial socketIOPort: number - socketIOToken?: string + socketIOSecret?: string httpTunnelPort?: number torAuthCookie?: string torControlPort?: number diff --git a/packages/common/src/jwt.ts b/packages/common/src/jwt.ts index bce6cbdd0b..30db4374ed 100644 --- a/packages/common/src/jwt.ts +++ b/packages/common/src/jwt.ts @@ -4,14 +4,15 @@ interface JwtPayload { appName: string } -const SECRET = 'secret' //temporary const APP_NAME = 'Quiet' -export const generateJWT = () => { - return sign({ appName: APP_NAME }, SECRET, { algorithm: 'HS256' }) +export const generateSecret = () => Math.floor(Math.random() * 100 ** 10).toString() + +export const generateJWT = (secret: string) => { + return sign({ appName: APP_NAME }, secret, { algorithm: 'HS256' }) } -export const verifyJWT = (token: string): boolean => { - const isVerify = verify(token, SECRET) as JwtPayload +export const verifyJWT = (token: string, secret: string): boolean => { + const isVerify = verify(token, secret) as JwtPayload return isVerify.appName === APP_NAME ? true : false } diff --git a/packages/desktop/src/main/main.ts b/packages/desktop/src/main/main.ts index 2d6cfa86a9..4d26ce2c58 100644 --- a/packages/desktop/src/main/main.ts +++ b/packages/desktop/src/main/main.ts @@ -11,7 +11,7 @@ import { Crypto } from '@peculiar/webcrypto' import logger from './logger' import { DATA_DIR, DEV_DATA_DIR } from '../shared/static' import { fork, ChildProcess } from 'child_process' -import { generateJWT, getFilesData } from '@quiet/common' +import { generateJWT, generateSecret, getFilesData } from '@quiet/common' import { updateDesktopFile, processInvitationCode } from './invitation' import { argvInvitationCode, retrieveInvitationCode } from '@quiet/common' const ElectronStore = require('electron-store') @@ -30,7 +30,7 @@ const updaterInterval = 15 * 60_000 export const isDev = process.env.NODE_ENV === 'development' export const isE2Etest = process.env.E2E_TEST === 'true' -const SOCKET_IO_TOKEN = generateJWT() +const SOCKET_IO_SECRET = generateSecret() const webcrypto = new Crypto() @@ -207,7 +207,7 @@ export const createWindow = async () => { mainWindow.loadURL( url.format({ pathname: path.join(__dirname, './index.html'), - search: `dataPort=${ports.dataServer}&socketIOToken=${SOCKET_IO_TOKEN}`, + search: `dataPort=${ports.dataServer}&socketIOSecret=${SOCKET_IO_SECRET}`, protocol: 'file:', slashes: true, hash: '/', @@ -364,8 +364,8 @@ app.on('ready', async () => { `${process.resourcesPath}`, '-p', 'desktop', - '-tkn', - `${SOCKET_IO_TOKEN}`, + '-scrt', + `${SOCKET_IO_SECRET}`, ] const backendBundlePath = path.normalize(require.resolve('backend-bundle')) diff --git a/packages/desktop/src/renderer/sagas/index.saga.ts b/packages/desktop/src/renderer/sagas/index.saga.ts index 21f09e60b8..3c5c94a9b9 100644 --- a/packages/desktop/src/renderer/sagas/index.saga.ts +++ b/packages/desktop/src/renderer/sagas/index.saga.ts @@ -6,13 +6,13 @@ import { socketActions } from './socket/socket.slice' export default function* root(): Generator { const dataPort = new URLSearchParams(window.location.search).get('dataPort') || '' - const socketIOToken = new URLSearchParams(window.location.search).get('socketIOToken') || '' + const socketIOSecret = new URLSearchParams(window.location.search).get('socketIOSecret') || '' yield all([ takeEvery(communities.actions.handleInvitationCode.type, handleInvitationCodeSaga), startConnectionSaga( socketActions.startConnection({ dataPort: parseInt(dataPort), - socketIOToken, + socketIOSecret, }) ), ]) diff --git a/packages/desktop/src/renderer/sagas/socket/socket.saga.ts b/packages/desktop/src/renderer/sagas/socket/socket.saga.ts index f50c4e9dfa..ea87398291 100644 --- a/packages/desktop/src/renderer/sagas/socket/socket.saga.ts +++ b/packages/desktop/src/renderer/sagas/socket/socket.saga.ts @@ -5,22 +5,23 @@ import { socket as stateManager, messages } from '@quiet/state-manager' import { socketActions } from './socket.slice' import { eventChannel } from 'redux-saga' import { displayMessageNotificationSaga } from '../notifications/notifications.saga' - import logger from '../../logger' +import { generateJWT } from '@quiet/common' + const log = logger('socket') export function* startConnectionSaga( action: PayloadAction['payload']> ): Generator { - const { dataPort, socketIOToken } = action.payload + const { dataPort, socketIOSecret } = action.payload if (!dataPort) { log.error('About to start connection but no dataPort found') } - + const jwtToken = generateJWT(socketIOSecret) const socket = yield* call(io, `http://127.0.0.1:${dataPort}`, { withCredentials: true, extraHeaders: { - authorization: `Bearer ${socketIOToken}`, + authorization: `Bearer ${jwtToken}`, }, }) yield* fork(handleSocketLifecycleActions, socket) diff --git a/packages/desktop/src/renderer/sagas/socket/socket.slice.ts b/packages/desktop/src/renderer/sagas/socket/socket.slice.ts index efe2d888c8..1658d9d7a5 100644 --- a/packages/desktop/src/renderer/sagas/socket/socket.slice.ts +++ b/packages/desktop/src/renderer/sagas/socket/socket.slice.ts @@ -9,7 +9,7 @@ export class SocketState { export interface WebsocketConnectionPayload { dataPort: number - socketIOToken: string + socketIOSecret: string } export interface CloseConnectionPayload { diff --git a/packages/desktop/src/renderer/testUtils/prepareStore.ts b/packages/desktop/src/renderer/testUtils/prepareStore.ts index 06de700142..d512dd15b8 100644 --- a/packages/desktop/src/renderer/testUtils/prepareStore.ts +++ b/packages/desktop/src/renderer/testUtils/prepareStore.ts @@ -119,5 +119,5 @@ function* mockSocketConnectionSaga(socket: MockedSocket): Generator { socket.socketClient.emit('connect') }) }) - yield* put(socketActions.startConnection({ dataPort: 4677, socketIOToken: 'testToken' })) + yield* put(socketActions.startConnection({ dataPort: 4677, socketIOSecret: '010101010' })) }