fix post window close auth bug

This commit is contained in:
Enrique Hernandez 2021-02-10 22:34:07 -06:00
commit 6a19a96855
7 changed files with 91 additions and 82 deletions

View file

@ -13,7 +13,12 @@ module.exports = {
}, },
rules: { rules: {
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off", "no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off" "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{ "argsIgnorePattern": "^_" }
]
}, },
overrides: [ overrides: [
{ {
@ -23,7 +28,7 @@ module.exports = {
"*.js" "*.js"
], ],
rules: { rules: {
"@typescript-eslint/no-var-requires": "off" "@typescript-eslint/no-var-requires": "off",
}, },
env: { env: {
jest: true jest: true

View file

@ -1,7 +1,9 @@
"use strict"; "use strict";
import { BrowserWindow } from "electron"; import { BrowserWindow, ipcMain } from "electron";
import { createProtocol } from "vue-cli-plugin-electron-builder/lib"; import { createProtocol } from "vue-cli-plugin-electron-builder/lib";
import { windowEmitter } from './windowEmitter';
import { sendMessage } from './session';
import * as path from "path"; import * as path from "path";
interface WindowSettings { interface WindowSettings {
@ -10,8 +12,17 @@ interface WindowSettings {
resizable: boolean; resizable: boolean;
} }
const handleMessage = (event: any, arg: any) => {
sendMessage(arg);
}
const windowMount = (): void => {
windowEmitter.emit('window-active', true);
ipcMain.on('send-message', handleMessage);
}
export const createWindow = async (options: WindowSettings): Promise<BrowserWindow> => { export const createWindow = async (options: WindowSettings): Promise<BrowserWindow> => {
return new Promise((resolve, reject) => { return new Promise((resolve, _reject) => {
const win: BrowserWindow = new BrowserWindow({ const win: BrowserWindow = new BrowserWindow({
width: options.width, width: options.width,
height: options.height, height: options.height,
@ -35,8 +46,10 @@ export const createWindow = async (options: WindowSettings): Promise<BrowserWind
} }
win.webContents.on('did-finish-load', () => { win.webContents.on('did-finish-load', () => {
windowMount();
resolve(win); resolve(win);
}); });
})
} });
};

View file

@ -1,58 +1,50 @@
"use strict";
import { createWindow } from './createWindow'; import { createWindow } from './createWindow';
import { ipcMain, BrowserWindow } from "electron"; import { ipcMain, BrowserWindow } from "electron";
import { initSession, sendMessage } from './session'; import { initSession } from './session';
import { windowEmitter } from './windowEmitter'; import { windowEmitter } from './windowEmitter';
const portAudio = require('naudiodon'); // const portAudio = require('naudiodon');
interface ipcRendererPayload { interface IpcRendererPayload {
endpoint: string; endpoint: string;
message: any; message: any;
} }
let activeSession = false;
let win: BrowserWindow | null; let win: BrowserWindow | null;
let activeSession = false;
windowEmitter.on('ipc-renderer', (payload: ipcRendererPayload) => { windowEmitter.on('ipc-renderer', (payload: IpcRendererPayload) => {
if (win) if (win)
win.webContents.send(payload.endpoint, { win.webContents.send(payload.endpoint, {
message: payload.message message: payload.message
}); });
}); });
/*
* The main function will be run after electron app is ready.
*/
export async function main() {
// create main window.
if (!win) {
win = await createWindow({ width: 350, height: 525, resizable: false });
}
// Instantiate socket session with crimata-platorm.
if (!activeSession) {
initSession();
}
activeSession = true;
const handleMessage = (event: any, arg: any) => {
sendMessage(arg);
}
const windowMount = (): void => {
windowEmitter.emit('window-active', true);
ipcMain.on('send-message', handleMessage);
}
const windowDismount = (): void => { const windowDismount = (): void => {
win = null; win = null;
windowEmitter.emit('window-active', false); windowEmitter.emit('window-active', false);
ipcMain.removeAllListeners('send-message'); ipcMain.removeAllListeners('send-message');
} }
// Handle window mount and dismount. /*
win.webContents.on('did-finish-load', windowMount); * The main function will be run after electron app is ready.
*/
export async function main() {
// create main window.
if (!win) win = await createWindow({
width: 350,
height: 525,
resizable: false
});
// Instantiate socket session with crimata-platorm.
if (!activeSession) initSession();
activeSession = true;
// Handle window close.
win.on("closed", windowDismount); win.on("closed", windowDismount);
// TODO: FIX recorder restart bug // TODO: FIX recorder restart bug

View file

@ -1,15 +1,10 @@
"use strict";
import WebSocket from 'ws'; import WebSocket from 'ws';
import { windowEmitter } from './windowEmitter'; import { windowEmitter } from './windowEmitter';
import { ipcMain } from "electron"; import { ipcMain } from "electron";
const EventEmitter = require('events');
class SocketEmitter extends EventEmitter {}
export const socketEmitter = new SocketEmitter();
interface RenderMessage { interface RenderMessage {
type: 'render';
content: string; content: string;
context: string; context: string;
subContext: string; subContext: string;
@ -33,24 +28,21 @@ let auth = false;
const receiveMessage = (message: string): void => { const receiveMessage = (message: string): void => {
while(!auth) { while(!auth) {
console.log('window emitter @ session.ts recieve')
windowEmitter.emit('auth-res', message); windowEmitter.emit('auth-res', message);
return; return;
} }
const parsed: RenderMessage = JSON.parse(message); const parsed: RenderMessage = JSON.parse(message);
if (parsed.type === "render") {
windowEmitter.emit('ipc-renderer', { windowEmitter.emit('ipc-renderer', {
endpoint: 'render-message', endpoint: 'render-message',
message: parsed message: parsed
}); });
} };
}
const authUser = async (event: any, payload: string | UserCreds | null): Promise<string> => { const authSession = async (_event, payload: string | UserCreds | null): Promise<string> => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
console.log('authenticating...'); console.log('authenticating...');
console.log('window emitter @ session.ts auth')
windowEmitter.on('auth-res', (res: string) => { windowEmitter.on('auth-res', (res: string) => {
if (res === 'locked') { if (res === 'locked') {
reject(res); reject(res);
@ -69,6 +61,14 @@ const authUser = async (event: any, payload: string | UserCreds | null): Promise
}); });
}; };
export const sendMessage = (content: string | Buffer) => {
if (content instanceof Buffer) {
socket.send(content);
} else if (content){
socket.send(JSON.stringify(content));
}
}
export const initSession = () => { export const initSession = () => {
if (socket) { if (socket) {
socket.removeAllListeners(); socket.removeAllListeners();
@ -84,7 +84,7 @@ export const initSession = () => {
// handle renderer auth-token event // handle renderer auth-token event
ipcMain.removeHandler('auth-user'); // avoid setting duplicate handlers ipcMain.removeHandler('auth-user'); // avoid setting duplicate handlers
ipcMain.handle('auth-user', authUser); ipcMain.handle('auth-user', authSession);
socket.on('open', () => { socket.on('open', () => {
console.log('Success! Connected to Crimata.'); console.log('Success! Connected to Crimata.');
@ -98,7 +98,7 @@ export const initSession = () => {
}); });
socket.on('error', (e) => { socket.on('error', (_e) => {
console.log('ERROR: Failed to connect.'); console.log('ERROR: Failed to connect.');
socket.removeAllListeners(); socket.removeAllListeners();
socket.close(); socket.close();
@ -109,20 +109,13 @@ export const initSession = () => {
} }
}, reconnectTimeout); }, reconnectTimeout);
}) });
socket.on('close', () => { socket.on('close', () => {
console.log('Connection droped. Restarting.') console.log('Connection droped. Restarting.')
initSession(); initSession();
}) });
socket.on("message", receiveMessage); socket.on("message", receiveMessage);
} };
export const sendMessage = (content: string | Buffer) => {
if (content instanceof Buffer) {
socket.send(content);
} else if (content){
socket.send(JSON.stringify(content));
}
}

View file

@ -1,13 +1,13 @@
import { reactive, watch, toRefs } from 'vue'; import { reactive, toRefs } from 'vue';
import { useIpc } from './ipc'; import { useIpc } from './ipc';
interface AuthState { interface AuthState {
access_token?: string | null; accessToken?: string | null;
error?: Error; error?: Error;
} }
const state = reactive<AuthState>({ const state = reactive<AuthState>({
access_token: undefined, accessToken: undefined,
error: undefined, error: undefined,
}); });
@ -15,20 +15,28 @@ const AUTH_KEY = 'crimata_token';
const token = window.localStorage.getItem(AUTH_KEY); const token = window.localStorage.getItem(AUTH_KEY);
// authenticate on socket connect const authToken = async () => {
window.ipcRenderer.on("fetch-token", async (event, payload: null) => {
const { data, invoke } = useIpc('auth-user'); const { data, invoke } = useIpc('auth-user');
try { try {
await invoke(token); await invoke(token);
state.access_token = data.value; state.accessToken = data.value;
} }
catch(e) { catch(e) {
state.error = e; state.error = e;
console.log('ERROR: failed authentication'); console.log('ERROR: failed authentication');
window.localStorage.removeItem(AUTH_KEY); window.localStorage.removeItem(AUTH_KEY);
} }
}
// authenticate on socket connect
window.ipcRenderer.on("fetch-token", async (_event, _arg) => {
authToken();
}); });
if (token) {
authToken();
}
export const useAuth = () => { export const useAuth = () => {
const setToken = (token: string, remember: boolean) => { const setToken = (token: string, remember: boolean) => {
if (remember) { if (remember) {
@ -36,18 +44,18 @@ export const useAuth = () => {
window.localStorage.setItem(AUTH_KEY, token); window.localStorage.setItem(AUTH_KEY, token);
} }
state.access_token = token; state.accessToken = token;
state.error = undefined; state.error = undefined;
} }
const logout = (): Promise<void> => { const logout = (): Promise<void> => {
window.localStorage.removeItem(AUTH_KEY); window.localStorage.removeItem(AUTH_KEY);
return Promise.resolve(state.access_token = undefined); return Promise.resolve(state.accessToken = undefined);
} }
return { return {
setToken, setToken,
logout, logout,
...toRefs(state), // access_token, error ...toRefs(state), // accessToken, error
} }
} }

View file

@ -35,13 +35,13 @@ const router = createRouter({
}); });
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
const { access_token } = useAuth(); const { accessToken } = useAuth();
// Not logged into a guarded route? // Not logged into a guarded route?
if (to.meta.requiresAuth && !access_token?.value) next({ name: 'login' }); if (to.meta.requiresAuth && !accessToken?.value) next({ name: 'login' });
// Logged in for an auth route // Logged in for an auth route
else if ((to.name == 'login' || to.name == 'register') && access_token!.value) next({ name: 'home' }); else if ((to.name == 'login' || to.name == 'register') && accessToken!.value) next({ name: 'home' });
// Carry On... // Carry On...
else next(); else next();

View file

@ -21,7 +21,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, toRefs, reactive, watch, ref } from "vue"; import { defineComponent, ref } from "vue";
import { useAuth } from "@/modules/auth"; import { useAuth } from "@/modules/auth";
import { useIpc } from "@/modules/ipc"; import { useIpc } from "@/modules/ipc";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
@ -35,14 +35,14 @@ interface LoginPayload {
export default defineComponent({ export default defineComponent({
name: "Login", name: "Login",
setup() { setup() {
const { setToken, access_token } = useAuth(); const { setToken } = useAuth();
const router = useRouter(); const router = useRouter();
const email = ref(""); const email = ref("");
const password = ref(""); const password = ref("");
const rememberMe = ref(false); const rememberMe = ref(false);
const { loading, error, data, invoke, errorMessage } = useIpc('auth-user'); const { data, invoke } = useIpc('auth-user');
const submit = async () => { const submit = async () => {
const payload = { const payload = {
@ -60,9 +60,7 @@ export default defineComponent({
}; };
return { return {
loading,
submit, submit,
errorMessage,
email, email,
password, password,
rememberMe rememberMe