From 277d92d97ac6aa84e0e10d8d6378e92d9906908a Mon Sep 17 00:00:00 2001 From: Valerie Date: Sat, 30 Jul 2022 04:07:38 -0400 Subject: [PATCH] begin authentication --- packages/renderer/src/pages/Chat.tsx | 13 ++++++---- .../server/src/db/snippets/session/get.sql | 12 ++++++++++ .../src/db/snippets/session/invalidate.sql | 3 +++ packages/server/src/lib/WebSocketServer.ts | 8 ++++++- packages/server/src/routers/account.ts | 10 -------- packages/server/src/routers/message.ts | 12 ++++++++-- packages/server/src/routers/session.ts | 24 +++++++++++++++++++ 7 files changed, 64 insertions(+), 18 deletions(-) create mode 100644 packages/server/src/db/snippets/session/get.sql create mode 100644 packages/server/src/db/snippets/session/invalidate.sql delete mode 100644 packages/server/src/routers/account.ts create mode 100644 packages/server/src/routers/session.ts diff --git a/packages/renderer/src/pages/Chat.tsx b/packages/renderer/src/pages/Chat.tsx index cf5155f..9572949 100644 --- a/packages/renderer/src/pages/Chat.tsx +++ b/packages/renderer/src/pages/Chat.tsx @@ -6,6 +6,7 @@ import { Message } from './Message'; import { MdSend } from 'react-icons/md'; import useChannel from '../hooks/useChannel'; import useClientId from '../hooks/useClientId'; +import useSessionToken from '../hooks/useSessionToken'; function createMessage(from: string, text: string, channel: string, t = 0): IMessage { @@ -21,6 +22,7 @@ function createMessage(from: string, text: string, export default () => { const [messages, setMessages] = useState([]); const [hist, setHist] = useState(false); + const { sessionToken } = useSessionToken(); const CHATBOX_SIZE = 64; const PADDING = 8; @@ -42,23 +44,24 @@ export default () => { }, [messages]); useEffect(() => { - send('message:recent', { channel }); - }, [channel]); + send('message:recent', { channel, sessionToken }); + }, [channel, sessionToken]); const sendMessage = useCallback(() => { if(textBoxRef.current === null) return; if(channel === null) return; if(clientId === null) return; + if(sessionToken === null) return; send( 'message:message', - createMessage( + { ...createMessage( clientId, textBoxRef.current.innerText, channel, - ), + ), sessionToken }, ); textBoxRef.current.innerText = ''; - }, [channel]); + }, [channel, sessionToken]); const keyDown = useCallback((evt: any) => { if(evt.key === 'Enter') { diff --git a/packages/server/src/db/snippets/session/get.sql b/packages/server/src/db/snippets/session/get.sql new file mode 100644 index 0000000..025e35d --- /dev/null +++ b/packages/server/src/db/snippets/session/get.sql @@ -0,0 +1,12 @@ +SELECT + sessions.client_uid as client_uid, + sessions.expires as expires, + clients.username as username +FROM sessions +JOIN clients + ON sessions.client_uid=clients.uid +WHERE + sessions.expires > UNIX_TIMESTAMP() * 1000 + AND sessions.token=? + +LIMIT 1; \ No newline at end of file diff --git a/packages/server/src/db/snippets/session/invalidate.sql b/packages/server/src/db/snippets/session/invalidate.sql new file mode 100644 index 0000000..74b6594 --- /dev/null +++ b/packages/server/src/db/snippets/session/invalidate.sql @@ -0,0 +1,3 @@ +UPDATE sessions +SET expires=UNIX_TIMESTAMP() * 1000 +WHERE token=?; \ No newline at end of file diff --git a/packages/server/src/lib/WebSocketServer.ts b/packages/server/src/lib/WebSocketServer.ts index f649aeb..e5d41d2 100644 --- a/packages/server/src/lib/WebSocketServer.ts +++ b/packages/server/src/lib/WebSocketServer.ts @@ -1,5 +1,6 @@ import { WebSocketServer } from 'ws'; import { inspect } from 'util'; +import { validateSessionToken } from '../routers/session'; export function expose(router: Function, port: number) { const wss = new WebSocketServer({ @@ -18,9 +19,14 @@ export function expose(router: Function, port: number) { } const {action, data} = message; try { + if(typeof data === 'object' && 'sessionToken' in data) { + const auth = await validateSessionToken(data.sessionToken); + delete data['sessionToken']; + if(auth === null) return; + data.$clientId = auth; + } console.log('[IN]', action, data); const _return = await (router(action, data) as unknown as Promise); - // console.log(_return); if(_return) { try { switch(_return.type) { diff --git a/packages/server/src/routers/account.ts b/packages/server/src/routers/account.ts deleted file mode 100644 index 979c0e3..0000000 --- a/packages/server/src/routers/account.ts +++ /dev/null @@ -1,10 +0,0 @@ -import router from "../lib/router"; - - - - -export default router({ - async create() { - - } -}) \ No newline at end of file diff --git a/packages/server/src/routers/message.ts b/packages/server/src/routers/message.ts index 3258fff..11008a3 100644 --- a/packages/server/src/routers/message.ts +++ b/packages/server/src/routers/message.ts @@ -7,22 +7,30 @@ import { broadcast, reply } from '../lib/WebSocketServer'; export default router({ async message(data: any) { + if(!('$clientId' in data)) { + console.error('unauthenticated message rejected.'); + return null; + } const response = await query( newMessage, data.text, - data.from, + data.$clientId, data.uid, data.timestamp, data.channel, ); if(response === null) return; // translate from to a real name - const nameRes = await query(getName, data.from); + const nameRes = await query(getName, data.$clientId); if(nameRes === null) return; data.from = nameRes[0].name; return broadcast(data); }, async recent(data: any) { + if(!('$clientId' in data)) { + console.error('unauthenticated request rejected.'); + return null; + } const messages = await query(recentMessages, data.channel); if(messages === null) return; return reply({ diff --git a/packages/server/src/routers/session.ts b/packages/server/src/routers/session.ts new file mode 100644 index 0000000..a589683 --- /dev/null +++ b/packages/server/src/routers/session.ts @@ -0,0 +1,24 @@ +import router from "../lib/router" +import { reply } from "../lib/WebSocketServer" + +import invalidate from '../db/snippets/session/invalidate.sql' +import _get from '../db/snippets/session/get.sql' +import query from "../db/query"; + +export default router({ + async 'invalidate'(token: string) { + await query(invalidate, token); + return reply({ + err: null + }) + } +}); + +export async function validateSessionToken(token: string) { + console.log('ASDASDASDASD') + const res = await query(_get, token); + if(res === null) return null; + if(res.length === 1 && res[0].expires > Date.now()) + return res[0].client_uid; + return null; +} \ No newline at end of file