From e0da50eb27af224e02426604bc375f6594362c1a Mon Sep 17 00:00:00 2001 From: Enrique Hernandez Date: Tue, 9 Feb 2021 17:07:45 -0600 Subject: [PATCH] add authenticate on socket connect --- src/background/run.ts | 11 +---- src/background/session.ts | 87 ++++++++++++++++++++------------------- src/modules/auth.ts | 17 +++++++- src/modules/ipc.ts | 17 +++++++- src/modules/socket.ts | 17 ++++++++ src/views/login.vue | 23 +++++------ testServer.js | 10 +++-- 7 files changed, 112 insertions(+), 70 deletions(-) create mode 100644 src/modules/socket.ts diff --git a/src/background/run.ts b/src/background/run.ts index 4c2404a..b8af002 100644 --- a/src/background/run.ts +++ b/src/background/run.ts @@ -14,12 +14,6 @@ interface ipcRendererPayload { */ export function main(): void { - // Instantiate socket session with crimata-platorm. - initSession(); - - // mount auth-user listener - ipcMain.on('auth-user', authUser); - // create main window. const win = createWindow({ width: 350, height: 525, resizable: false }); @@ -34,18 +28,17 @@ export function main(): void { } const windowMount = (): void => { + // Instantiate socket session with crimata-platorm. + initSession(); windowEmitter.emit('window-active', true); - // ipc event handlers ipcMain.on('send-message', handleMessage); ipcMain.on('auth-login', authLogin); } const windowDismount = (): void => { windowEmitter.emit('window-active', false); - // TODO: Gracefully close socket connection ipcMain.removeAllListeners('send-message'); ipcMain.removeAllListeners('auth-login'); - ipcMain.removeAllListeners('auth-user'); } // Handle window mount and dismount. diff --git a/src/background/session.ts b/src/background/session.ts index 55d30b0..4612757 100644 --- a/src/background/session.ts +++ b/src/background/session.ts @@ -1,5 +1,6 @@ import WebSocket from 'ws'; import { windowEmitter } from './windowEmitter'; +import { ipcMain } from "electron"; type Message = { type: string; @@ -14,85 +15,87 @@ interface RenderMessage extends Message { time: string; } -interface AuthMessage extends Message { +interface AuthUser extends Message { email: string; firstName: string; lastName: string; access_token: string; } -interface AuthRequest { - token: string; -} - -interface PostLogin { - email: string; - password: string; -} - -interface PostMessage { - content: string; -} - const ip = 'ws://localhost'; const port = 8080; -const username = 'hernandeze2@xavier.edu'; +const reconnectTimeout = 3000; //ms let socket: WebSocket; +let success = false; const receiveMessage = (message: string): void => { // NOTE assuming message is JSON string - const parsed: RenderMessage | AuthMessage = JSON.parse(message); + if (message === 'locked') { + windowEmitter.emit('auth-resp', message); + return; + } + const parsed: RenderMessage | AuthUser = JSON.parse(message); if (parsed.type === "render") { windowEmitter.emit('ipc-renderer', { endpoint: 'render-message', message: parsed }); - } else if (parsed.type === "auth") { - windowEmitter.emit('auth-resp', parsed); } } -// Connect and send username +const authToken = async (event: any, token: string): Promise => { + return new Promise((resolve, reject) => { + console.log('authenticating...'); + windowEmitter.on('auth-resp', (arg: string | AuthUser) => { + if (arg === 'locked') { + reject(arg); + } + resolve(arg); + }); + if (token) { + socket.send(token); + } else { + socket.send('no-token'); + } + }); +}; + +// Connect and authenticate export function initSession() { - let success = false; socket = new WebSocket(`${ip}:${port}`); socket.binaryType = 'arraybuffer'; socket.on('open', () => { console.log('Connected to crimata-platform'); - socket.send(username); success = true; + + // handle renderer auth-token event + ipcMain.removeHandler('auth-token'); // avoid setting duplicate handlers + ipcMain.handle('auth-token', authToken); + + // fetch token from renderer + windowEmitter.emit('ipc-renderer', { + endpoint: 'fetch-token', + message: null + }); + }) socket.on("message", receiveMessage); setTimeout(()=> { if (!success) { - throw new Error('Unable to connect to crimata-platform') + // initSession(); + throw new Error('Unable to connect to crimata-platform'); } - }, 3000) -} - -export const authUser = (event: any, arg: AuthRequest) => { - console.log('sending token to socket', arg) - try { - sendMessage({ - content: arg.token - }); - windowEmitter.on('auth-resp', (payload: AuthMessage) => { - event.reply('auth-user-reply', payload); - }) - } catch(e){ - console.log('Error authenticating user! ' + e); - event.reply('auth-user-reply', e); - } + }, reconnectTimeout); } -export const authLogin = (event: any, arg: PostLogin) => { +export const authLogin = (event: any, arg: any) => { try { sendMessage(arg) - windowEmitter.on('auth-resp', (payload: AuthMessage) => { + windowEmitter.on('auth-resp', (payload: AuthUser) => { event.reply('auth-login-reply', payload); }) } catch(e) { @@ -101,10 +104,10 @@ export const authLogin = (event: any, arg: PostLogin) => { } } -export const sendMessage = (content: PostMessage | Buffer | PostLogin) => { +export const sendMessage = (content: string | Buffer) => { if (content instanceof Buffer) { socket.send(content); - } else { + } else if (content){ socket.send(JSON.stringify(content)); } } diff --git a/src/modules/auth.ts b/src/modules/auth.ts index 16be95c..ec8e444 100644 --- a/src/modules/auth.ts +++ b/src/modules/auth.ts @@ -24,10 +24,23 @@ const state = reactive({ const AUTH_KEY = 'crimata_token'; const token = window.localStorage.getItem(AUTH_KEY); -console.log('token: ',token) + +// authenticate on socket connect +window.ipcRenderer.on("fetch-token", async (event, payload) => { + const { data, invoke } = useIpc('auth-token'); + try { + await invoke(token); + state.user = data.value; + } + catch(e) { + state.error = e; + console.log('ERROR: failed authentication'); + window.localStorage.removeItem(AUTH_KEY); + } +}); if (token) { - const { loading, error, data, send } = useIpc('auth-user'); + const { loading, error, data, send, invoke } = useIpc('auth-user'); state.authenticating = true; diff --git a/src/modules/ipc.ts b/src/modules/ipc.ts index aebe903..dbf191b 100644 --- a/src/modules/ipc.ts +++ b/src/modules/ipc.ts @@ -13,6 +13,20 @@ export const useIpc = (endpoint: string) => { } }) + const invoke = (payload: any) => { + loading.value = true; + error.value = undefined; + + return window.ipcRenderer.invoke(endpoint, payload).then(res => { + data.value = res; + }).catch(e => { + error.value = e; + throw e; + }).finally(() => { + loading.value = false; + }) + } + const send = (payload?: Record, callback?: (arg: any) => void) => { loading.value = true; error.value = undefined; @@ -46,6 +60,7 @@ export const useIpc = (endpoint: string) => { data, error, errorMessage, - send + send, + invoke } } diff --git a/src/modules/socket.ts b/src/modules/socket.ts new file mode 100644 index 0000000..07f3dbb --- /dev/null +++ b/src/modules/socket.ts @@ -0,0 +1,17 @@ +interface SocketState { + connection: WebSocket | null; + auth: boolean; +} + +// Create WebSocket connection. +const socket = new WebSocket('ws://localhost:8080'); + +// Connection opened +socket.onopen = function (event) { + socket.send('Hello Server!'); +} + +socket.onmessage = function(event) { + console.debug("WebSocket message received:", event); +} + diff --git a/src/views/login.vue b/src/views/login.vue index a887bf1..185b231 100644 --- a/src/views/login.vue +++ b/src/views/login.vue @@ -41,24 +41,21 @@ export default defineComponent({ rememberMe: true, }); - const { loading, data, send, errorMessage } = useIpc("auth-login"); + //const { loading, data, send, errorMessage } = useIpc("auth-login"); + const { loading, error, data, invoke, errorMessage } = useIpc('test'); const submit = async () => { // console.log(toRefs(payload)); - send({ - request: "register", - email: payload.email, - password: payload.password, - }); - console.log(data.value, "login"); + await invoke({ + request: "register", + email: payload.email, + password: payload.password, + }) + console.log('testing incoke', data.value.test) + // setUser(data.value, payload.rememberMe); + router.push({ name: "home" }); }; - watch(loading, () => { - console.log(data.value) - setUser(data.value, payload.rememberMe); - router.push({ name: "home" }); - }); - return { loading, submit, diff --git a/testServer.js b/testServer.js index 6c8fbc8..3d9864f 100644 --- a/testServer.js +++ b/testServer.js @@ -14,12 +14,16 @@ const wss = new WebSocket.Server({ wss.on("connection", function connection(ws, req) { ws.on("message", function incoming(message) { + console.log(message) - // const parsed = JSON.parse(message) - // console.log(parsed) + if (message === 'no-token') { + console.log('no token to authenticate'); + ws.send('locked'); + } + }); const ip = req.socket.remoteAddress; console.log("received connection from", ip); - ws.send(JSON.stringify(testMessage)); + // ws.send(JSON.stringify(testMessage)); }); -- 2.43.0