add authenticate on socket connect

This commit is contained in:
Enrique Hernandez 2021-02-09 17:07:45 -06:00
commit e0da50eb27
7 changed files with 112 additions and 70 deletions

View file

@ -14,12 +14,6 @@ interface ipcRendererPayload {
*/ */
export function main(): void { export function main(): void {
// Instantiate socket session with crimata-platorm.
initSession();
// mount auth-user listener
ipcMain.on('auth-user', authUser);
// create main window. // create main window.
const win = createWindow({ width: 350, height: 525, resizable: false }); const win = createWindow({ width: 350, height: 525, resizable: false });
@ -34,18 +28,17 @@ export function main(): void {
} }
const windowMount = (): void => { const windowMount = (): void => {
// Instantiate socket session with crimata-platorm.
initSession();
windowEmitter.emit('window-active', true); windowEmitter.emit('window-active', true);
// ipc event handlers
ipcMain.on('send-message', handleMessage); ipcMain.on('send-message', handleMessage);
ipcMain.on('auth-login', authLogin); ipcMain.on('auth-login', authLogin);
} }
const windowDismount = (): void => { const windowDismount = (): void => {
windowEmitter.emit('window-active', false); windowEmitter.emit('window-active', false);
// TODO: Gracefully close socket connection
ipcMain.removeAllListeners('send-message'); ipcMain.removeAllListeners('send-message');
ipcMain.removeAllListeners('auth-login'); ipcMain.removeAllListeners('auth-login');
ipcMain.removeAllListeners('auth-user');
} }
// Handle window mount and dismount. // Handle window mount and dismount.

View file

@ -1,5 +1,6 @@
import WebSocket from 'ws'; import WebSocket from 'ws';
import { windowEmitter } from './windowEmitter'; import { windowEmitter } from './windowEmitter';
import { ipcMain } from "electron";
type Message = { type Message = {
type: string; type: string;
@ -14,85 +15,87 @@ interface RenderMessage extends Message {
time: string; time: string;
} }
interface AuthMessage extends Message { interface AuthUser extends Message {
email: string; email: string;
firstName: string; firstName: string;
lastName: string; lastName: string;
access_token: string; access_token: string;
} }
interface AuthRequest {
token: string;
}
interface PostLogin {
email: string;
password: string;
}
interface PostMessage {
content: string;
}
const ip = 'ws://localhost'; const ip = 'ws://localhost';
const port = 8080; const port = 8080;
const username = 'hernandeze2@xavier.edu'; const reconnectTimeout = 3000; //ms
let socket: WebSocket; let socket: WebSocket;
let success = false;
const receiveMessage = (message: string): void => { const receiveMessage = (message: string): void => {
// NOTE assuming message is JSON string // 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") { if (parsed.type === "render") {
windowEmitter.emit('ipc-renderer', { windowEmitter.emit('ipc-renderer', {
endpoint: 'render-message', endpoint: 'render-message',
message: parsed message: parsed
}); });
} else if (parsed.type === "auth") {
windowEmitter.emit('auth-resp', parsed);
} }
} }
// Connect and send username const authToken = async (event: any, token: string): Promise<string | AuthUser > => {
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() { export function initSession() {
let success = false;
socket = new WebSocket(`${ip}:${port}`); socket = new WebSocket(`${ip}:${port}`);
socket.binaryType = 'arraybuffer'; socket.binaryType = 'arraybuffer';
socket.on('open', () => { socket.on('open', () => {
console.log('Connected to crimata-platform'); console.log('Connected to crimata-platform');
socket.send(username);
success = true; 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); socket.on("message", receiveMessage);
setTimeout(()=> { setTimeout(()=> {
if (!success) { if (!success) {
throw new Error('Unable to connect to crimata-platform') // initSession();
throw new Error('Unable to connect to crimata-platform');
} }
}, 3000) }, reconnectTimeout);
} }
export const authUser = (event: any, arg: AuthRequest) => { export const authLogin = (event: any, arg: any) => {
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);
}
}
export const authLogin = (event: any, arg: PostLogin) => {
try { try {
sendMessage(arg) sendMessage(arg)
windowEmitter.on('auth-resp', (payload: AuthMessage) => { windowEmitter.on('auth-resp', (payload: AuthUser) => {
event.reply('auth-login-reply', payload); event.reply('auth-login-reply', payload);
}) })
} catch(e) { } 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) { if (content instanceof Buffer) {
socket.send(content); socket.send(content);
} else { } else if (content){
socket.send(JSON.stringify(content)); socket.send(JSON.stringify(content));
} }
} }

View file

@ -24,10 +24,23 @@ const state = reactive<AuthState>({
const AUTH_KEY = 'crimata_token'; const AUTH_KEY = 'crimata_token';
const token = window.localStorage.getItem(AUTH_KEY); 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) { if (token) {
const { loading, error, data, send } = useIpc('auth-user'); const { loading, error, data, send, invoke } = useIpc('auth-user');
state.authenticating = true; state.authenticating = true;

View file

@ -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<string, any>, callback?: (arg: any) => void) => { const send = (payload?: Record<string, any>, callback?: (arg: any) => void) => {
loading.value = true; loading.value = true;
error.value = undefined; error.value = undefined;
@ -46,6 +60,7 @@ export const useIpc = (endpoint: string) => {
data, data,
error, error,
errorMessage, errorMessage,
send send,
invoke
} }
} }

17
src/modules/socket.ts Normal file
View file

@ -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);
}

View file

@ -41,23 +41,20 @@ export default defineComponent({
rememberMe: true, 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 () => { const submit = async () => {
// console.log(toRefs(payload)); // console.log(toRefs(payload));
send({ await invoke({
request: "register", request: "register",
email: payload.email, email: payload.email,
password: payload.password, password: payload.password,
}); })
console.log(data.value, "login"); console.log('testing incoke', data.value.test)
}; // setUser(data.value, payload.rememberMe);
watch(loading, () => {
console.log(data.value)
setUser(data.value, payload.rememberMe);
router.push({ name: "home" }); router.push({ name: "home" });
}); };
return { return {
loading, loading,

View file

@ -14,12 +14,16 @@ const wss = new WebSocket.Server({
wss.on("connection", function connection(ws, req) { wss.on("connection", function connection(ws, req) {
ws.on("message", function incoming(message) { ws.on("message", function incoming(message) {
console.log(message) console.log(message)
// const parsed = JSON.parse(message) if (message === 'no-token') {
// console.log(parsed) console.log('no token to authenticate');
ws.send('locked');
}
}); });
const ip = req.socket.remoteAddress; const ip = req.socket.remoteAddress;
console.log("received connection from", ip); console.log("received connection from", ip);
ws.send(JSON.stringify(testMessage)); // ws.send(JSON.stringify(testMessage));
}); });