From ea3fc85371d9c6d29f398b60eca74f5b9101f2bf Mon Sep 17 00:00:00 2001 From: riqo Date: Tue, 25 May 2021 09:01:28 -0500 Subject: [PATCH] add user-auth and init-session events --- package.json | 2 + src/App.vue | 45 ++++++++++++---- src/background/init.ts | 62 +++++++++++++++-------- src/background/session.ts | 56 ++++++++------------ src/{modules => background}/websockets.ts | 29 ++++++++--- src/background/window.ts | 4 -- src/modules/auth.ts | 34 +++++++++++++ yarn.lock | 19 +++++++ 8 files changed, 174 insertions(+), 77 deletions(-) rename src/{modules => background}/websockets.ts (70%) create mode 100644 src/modules/auth.ts diff --git a/package.json b/package.json index 961035f..369eac4 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "@types/uuid": "^8.3.0", "@types/ws": "^7.2.7", "animejs": "^3.2.0", + "axios": "^0.21.1", "core-js": "^3.6.5", "electron-is-dev": "^2.0.0", "electron-updater": "^4.3.8", @@ -36,6 +37,7 @@ "ws": "^7.3.1" }, "devDependencies": { + "@types/axios": "^0.14.0", "@types/electron-devtools-installer": "^2.2.0", "@types/jest": "^24.0.19", "@typescript-eslint/eslint-plugin": "^2.33.0", diff --git a/src/App.vue b/src/App.vue index 86d1007..af89d48 100644 --- a/src/App.vue +++ b/src/App.vue @@ -35,11 +35,13 @@ import { defineComponent, onMounted, onUnmounted, ref } from "vue"; import { IpcRendererEvent } from "electron"; import { useIpc } from "@/modules/ipc"; +import { useAuth } from "@/modules/auth" import Splash from "@/components/splash.vue"; import Messenger from "@/components/messenger.vue"; import Login from "@/components/login.vue"; + export default defineComponent({ components: { @@ -49,7 +51,10 @@ export default defineComponent({ }, setup() { - const { post } = useIpc(); + + const { post, invoke } = useIpc(); + + const { user } = useAuth(); // Whether browser has received user info yet. const ready = ref(false); @@ -58,18 +63,19 @@ export default defineComponent({ const profile = ref(false); // New messages that browser missed while closed. - const newMessages = ref([]) + const newMessages = ref([]); // Receive updated information about the session. const updateState = (_event: IpcRendererEvent, payload: any) => { + console.log('YAYAYAYAYA'); console.log("APP:Received updated profile and new messages: \n" + ` profile: ${payload.message.profile}\n` + - ` new: ${payload.message.newMessages}`) + ` new: ${payload.message.newMessages}`); if (payload.message.profile) { - console.log(`APP:Logged-in, showing Messenger View.`) + console.log(`APP:Logged-in, showing Messenger View.`); } else { - console.log(`APP:Logged-out, showing Login View.`) + console.log(`APP:Logged-out, showing Login View.`); } // Set profile and newMessages. @@ -81,8 +87,8 @@ export default defineComponent({ } - onMounted(() => { - console.log("APP:mounted.") + onMounted(async () => { + console.log("APP:mounted."); window.ipcRenderer.on("update-state", updateState) window.ipcRenderer.on("update_available", () => { console.log('testing auto update'); @@ -91,11 +97,32 @@ export default defineComponent({ window.ipcRenderer.on("update_downloaded", () => { console.log('testing update download'); }) - post("app-mounted", "") + + post("app-mounted", ""); + + if(user.value.key) { + try { + const res = await invoke('user-auth', JSON.stringify(user.value)); + profile.value = res; + } catch(e) { + profile.value = false; + console.log('[AUTH]', e); + } finally { + ready.value = true; + if (profile.value) { + // start session + post("init-session", user.value.email); + } + } + } else { + profile.value = false; + ready.value = true; + } + }); onUnmounted(() => { - window.ipcRenderer.removeAllListeners("update-state") + window.ipcRenderer.removeAllListeners("update-state"); }) return { diff --git a/src/background/init.ts b/src/background/init.ts index 5150d9f..be260e7 100644 --- a/src/background/init.ts +++ b/src/background/init.ts @@ -1,11 +1,12 @@ "use strict"; -import { app, dialog } from "electron"; +import { app, dialog, ipcMain, IpcMainInvokeEvent } from "electron"; import { createWindow } from './window'; -import { initSession, updateState } from './session'; +import { initSession, onAppMounted } from './session'; import { initAudioIO, stopStream } from './audio'; import { backgroundMitt } from '@/modules/emitter'; +import { Profile } from "@/types"; let win: boolean; @@ -38,36 +39,53 @@ autoUpdater.on('update-downloaded', (info: any) => { }) - -interface Profile { - crimataId: string; - alias: string; - initials: string; +interface AccountAuth { + email: string; + password?: string; + key: string | null; } -// Run when electron app is initialized. -async function main() { - console.log("MAIN:Initializing Electron App.") +const onUserAuth = async (_event: any, payload: AccountAuth) +:Promise => ( + new Promise((resolve, reject) => { - // Must wait til window is created. - await createWindow(); + // check for login + if (payload.password) { + // await user login - // authenticate against business backend - const auth = async (crimataId: string): Promise => { - updateState({key: "", profile: { - crimataId: "", - alias: "", - initials: "" - }}); - return null - }; - auth(''); + } else { + // authenticate token + } + }) +) +const onSessionInit = (_event: IpcMainInvokeEvent, payload: string) => { // Instantiate socket session with crimata-platorm. initSession(); // Begin audio stream. initAudioIO(); +} + + + +// Run when electron app is initialized. +async function main() { + + console.log("MAIN:Initializing Electron App."); + + // Attack browser window init listener. + ipcMain.removeAllListeners("app-mounted"); + ipcMain.on("app-mounted", onAppMounted); + + ipcMain.removeHandler("user-auth"); + ipcMain.handle("user-auth", onUserAuth); + + ipcMain.removeAllListeners("init-session"); + ipcMain.on("init-session", onSessionInit); + + // Must wait til window is created. + await createWindow(); } diff --git a/src/background/session.ts b/src/background/session.ts index 0a8b91d..8128a67 100644 --- a/src/background/session.ts +++ b/src/background/session.ts @@ -12,7 +12,7 @@ import { backgroundMitt } from "@/modules/emitter"; import { ipcEmit, loadState, saveToJson } from './helpers'; import { ipcMain, IpcMainEvent, IpcMainInvokeEvent } from "electron"; -import useWebSockets from "@/modules/websockets"; +import useWebSockets from "./websockets"; import { play } from "./audio"; import { renderMessage } from "@/modules/message"; @@ -56,22 +56,23 @@ export const updateState = (res: AuthProtocol) => { } // Send state on new window. -const onNewBrowserWindow = (_event: IpcMainInvokeEvent, _payload: any) => { +export const onAppMounted = (_event: IpcMainInvokeEvent, _payload: any) => { + + profile = true; + console.log('testing!!!', profile) if (typeof profile !== 'undefined') { - console.log("SESS:Sending user profile to browser.") + console.log("SESS:Sending user profile to browser."); ipcEmit("update-state", { profile: profile, - newMessages: state.newMessages - }) + newMessages: [], + }); } } // Calls appropriate endpoint for a server message. const onMessage = (data: string) => { - let message = JSON.parse(data) - - // AuthProtocol message. - updateState(message) + let message = JSON.parse(data); + console.log('received new message', message); // Standard message. if (message.content) { @@ -106,57 +107,42 @@ const onMessage = (data: string) => { }; -// When socket connects, we update state. -const onOpen = () => { - // console.log(`SESS:Sending key: ${state.key}`) - - if (state) { - // sendMessage({ - // "key": state.key, - // "usr": false, - // "pwd": false - // }) - } -} // Websockets module. -const { createSocket, sendMessage } = useWebSockets(onMessage, onOpen); +const { createSocket, send } = useWebSockets(onMessage); // Handle messages from window/client. -const onClientMessage = (_event: IpcMainEvent, payload: any) => { +const onClientMessage = async (_event: IpcMainEvent, payload: any):Promise => { console.log("New client message") if (payload.hasOwnProperty("key")) { return } - const success = sendMessage(payload); - - if (!success) { + try { + send(payload) + } catch(e) { console.log("Unable to send message: ", payload); } } + // Call this to initialize session with Crimata servers. export const initSession = () => { console.log("SESS:Creating new session.") // Load Json or createState. - state = loadState("session.json") - - console.log("SESS:State loaded: \n" + - ` key: ${state.key}\n` + - ` new: ${state.newMessages}`) + state = loadState("session.json"); // Open socket connection. - createSocket() + createSocket(); // Attack browser window init listener. - ipcMain.removeAllListeners("app-mounted") - ipcMain.on("app-mounted", onNewBrowserWindow); + // ipcMain.removeAllListeners("app-mounted"); + // ipcMain.on("app-mounted", onAppMounted); // Attach listeners for frontend. - ipcMain.removeAllListeners("client-message") + ipcMain.removeAllListeners("client-message"); ipcMain.on("client-message", onClientMessage); // Keep win up-to-date. diff --git a/src/modules/websockets.ts b/src/background/websockets.ts similarity index 70% rename from src/modules/websockets.ts rename to src/background/websockets.ts index 9af0448..a6ae482 100644 --- a/src/modules/websockets.ts +++ b/src/background/websockets.ts @@ -1,13 +1,16 @@ "use strict"; import WebSocket from 'ws'; -import { ipcMain } from "electron"; let socket: WebSocket; + // Run every time we want to connect to backend. -export default function useWebSockets(receiveCallback: (s: string) => any, openCallback: () => any) { +export default function useWebSockets( + receiveCallback: (s: string) => void, + openCallback?: () => void +) { // Returns bool (sucess or fail). const sendMessage = (data: any) => { @@ -24,11 +27,22 @@ export default function useWebSockets(receiveCallback: (s: string) => any, openC } - const onOpen = (event: WebSocket.OpenEvent) => { + const send = async (data: Record):Promise => ( + new Promise((resolve, reject) => { + if (socket.readyState !== 1) { + reject(false); + } + socket.send(JSON.stringify(data)) + resolve(true); + + })) + + + const onOpen = (_event: WebSocket.OpenEvent) => { console.log("WS:Connected to WS Server!"); - openCallback() + if (openCallback) openCallback(); } @@ -40,7 +54,7 @@ export default function useWebSockets(receiveCallback: (s: string) => any, openC } - const onClose = (event: WebSocket.CloseEvent) => { + const onClose = (_event: WebSocket.CloseEvent) => { console.log("WS:Socket closed normally.") } @@ -66,7 +80,8 @@ export default function useWebSockets(receiveCallback: (s: string) => any, openC return { createSocket, - sendMessage + sendMessage, + send } -} \ No newline at end of file +} diff --git a/src/background/window.ts b/src/background/window.ts index e312572..162b3e1 100644 --- a/src/background/window.ts +++ b/src/background/window.ts @@ -57,7 +57,6 @@ const saveWindowState = () => { // Do this on window mount. const onWindowMount = (): void => { - console.log("BW:Adding window listeners. ") // Must tell initApp that window exists. backgroundMitt.emit('window-active', true); @@ -70,12 +69,10 @@ const onWindowMount = (): void => { backgroundMitt.removeAllListeners("ipc-renderer") backgroundMitt.on("ipc-renderer", renderMessage); - console.log("BW:Listeners created.") } // Do this on window dismount (close). const onWindowDismount = (): void => { - console.log("BW:Window closed.") win = null; backgroundMitt.emit('window-active', false); } @@ -89,7 +86,6 @@ export async function createWindow(): Promise { // Load the saved window state. winState = loadWinState("window.json") - console.log(`BW:Creating window [${winState.width}, ${winState.height}].`) // Define the browser window. win = new BrowserWindow({ diff --git a/src/modules/auth.ts b/src/modules/auth.ts new file mode 100644 index 0000000..bba8bdd --- /dev/null +++ b/src/modules/auth.ts @@ -0,0 +1,34 @@ +import { ref, Ref} from "vue"; + +interface UserState { + email: string | null; + password?: string; + key: string | null; +} + +const user:Ref = ref({ + email: null, + key: "testing" +}); + +const CRIMATA_KEY = "CRIMATA_KEY"; + +const raw = window.localStorage.getItem(CRIMATA_KEY); + +if (raw) { + user.value = JSON.parse(raw); +} + +export const useAuth = () => { + + const setUser = (token: UserState) => { + window.localStorage.setItem(CRIMATA_KEY, JSON.stringify(token)); + user.value = token; + } + + return { + setUser, + user + } + +} diff --git a/yarn.lock b/yarn.lock index 8dc3fba..6d0785b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1279,6 +1279,13 @@ resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== +"@types/axios@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@types/axios/-/axios-0.14.0.tgz#ec2300fbe7d7dddd7eb9d3abf87999964cafce46" + integrity sha1-7CMA++fX3d1+udOr+HmZlkyvzkY= + dependencies: + axios "*" + "@types/babel__core@^7.1.0": version "7.1.12" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.12.tgz#4d8e9e51eb265552a7e4f1ff2219ab6133bdfb2d" @@ -2733,6 +2740,13 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== +axios@*, axios@^0.21.1: + version "0.21.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" + integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== + dependencies: + follow-redirects "^1.10.0" + babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -5871,6 +5885,11 @@ follow-redirects@^1.0.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA== +follow-redirects@^1.10.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43" + integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg== + for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" -- 2.43.0