updating login
This commit is contained in:
parent
9bf7496899
commit
bb9769e917
22 changed files with 316 additions and 362 deletions
83
src/App.vue
83
src/App.vue
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div id="app" v-if="ready">
|
||||
<div id="app" v-if="(windowReady && sessionReady)">
|
||||
|
||||
<button class="titlebar" />
|
||||
|
||||
|
|
@ -28,55 +28,90 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, onUnmounted, ref } from "vue";
|
||||
import { IpcRendererEvent } from "electron";
|
||||
import { authRequest } from '@/modules/message';
|
||||
import { useIpc } from "@/modules/ipc";
|
||||
import Splash from "@/components/splash.vue"
|
||||
|
||||
import Splash from "@/components/splash.vue";
|
||||
import Messenger from "@/components/messenger.vue";
|
||||
import Login from "@/components/login.vue";
|
||||
|
||||
export default defineComponent({
|
||||
components: { Splash },
|
||||
components: {
|
||||
Splash,
|
||||
Messenger,
|
||||
Login
|
||||
},
|
||||
|
||||
setup() {
|
||||
const { post, invoke } = useIpc();
|
||||
|
||||
const ready = ref(false);
|
||||
const auth = ref(false);
|
||||
const windowReady = ref(false);
|
||||
const sessionReady = ref(false);
|
||||
|
||||
// Whether user is logged in.
|
||||
let auth = ref(false);
|
||||
// When connection is established, we send key over.
|
||||
const onOpen = (_event: IpcRendererEvent, payload: any) => {
|
||||
console.log(`Connected to Crimata.`)
|
||||
const key = window.localStorage.getItem("key");
|
||||
|
||||
if (key) {
|
||||
console.log(`Sending key: ${key}`)
|
||||
post("client-message", authRequest(key, false, false))
|
||||
}
|
||||
|
||||
else {
|
||||
console.log("No key, session ready.")
|
||||
sessionReady.value = true
|
||||
}
|
||||
|
||||
// Attempt token login
|
||||
const key = window.localStorage.getItem(AUTH_KEY);
|
||||
|
||||
if (key) {
|
||||
post("client-message", key)
|
||||
}
|
||||
|
||||
// onAuthResponse
|
||||
const onAuthResponse = (_event: IpcMainEvent, payload: Auth) => {
|
||||
if (payload.token) {
|
||||
// Update authenticate state on auth message from server.
|
||||
const onAuthResponse = (_event: IpcRendererEvent, payload: any) => {
|
||||
const key = payload.message.key
|
||||
const usr = payload.message.usr
|
||||
console.log(`Received auth response: ${usr}, ${key}`)
|
||||
|
||||
if (key) {
|
||||
console.log(`Auth success, saving key: ${key}.`)
|
||||
window.localStorage.setItem("key", payload.message.key)
|
||||
auth.value = true;
|
||||
}
|
||||
|
||||
else {
|
||||
console.log(`Auth failed, clearing local storage.`)
|
||||
window.localStorage.clear()
|
||||
auth.value = false;
|
||||
}
|
||||
|
||||
console.log("Session is ready.")
|
||||
sessionReady.value = true
|
||||
|
||||
}
|
||||
|
||||
// Post navbar action to backend.
|
||||
const callNavbar = (action: string) => {
|
||||
post('nav-bar', action);
|
||||
invoke("nav-bar", action);
|
||||
}
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
window.ipcRenderer.on("auth-response", onAuthResponse)
|
||||
|
||||
|
||||
window.ipcRenderer.on("window-ready", () => ready.value = true);
|
||||
window.ipcRenderer.on("on-connect", onOpen)
|
||||
window.ipcRenderer.on("auth-response", onAuthResponse)
|
||||
window.ipcRenderer.on("window-ready", () => windowReady.value = true);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.ipcRenderer.removeAllListeners("window-ready")
|
||||
window.ipcRenderer.removeAllListeners("auth-response")
|
||||
window.ipcRenderer.removeAllListeners("on-connect")
|
||||
window.ipcRenderer.removeAllListeners("window-ready")
|
||||
window.ipcRenderer.removeAllListeners("auth-response")
|
||||
})
|
||||
|
||||
return {
|
||||
callNavbar,
|
||||
ready,
|
||||
auth,
|
||||
sessionReady,
|
||||
windowReady,
|
||||
auth
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -18,8 +18,6 @@ const audioContainer = {
|
|||
input: '',
|
||||
}
|
||||
|
||||
const encoding = "hex";
|
||||
|
||||
const audioOptions = {
|
||||
channelCount: 1,
|
||||
sampleFormat: 16,
|
||||
|
|
@ -28,21 +26,73 @@ const audioOptions = {
|
|||
closeOnError: false,
|
||||
}
|
||||
|
||||
// callback run on space bar key up and down.
|
||||
const updateRecorder = (_event, payload: { isRecording: boolean; uid: string | null;
|
||||
|
||||
}): void => {
|
||||
|
||||
record = payload.isRecording;
|
||||
if (!record) {
|
||||
if (payload.uid) sendAudio(audioContainer.input, payload.uid);
|
||||
}
|
||||
// Returns recorded audio to frontend and sets record to false.
|
||||
const onRecordingEnd = async (_event: any, payload: any) => {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
try {
|
||||
resolve(audioContainer.input);
|
||||
record = false;
|
||||
} catch (e) {
|
||||
reject()
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
// listen for space key up/down event.
|
||||
ipcMain.removeAllListeners('update-recorder');
|
||||
ipcMain.on('update-recorder', updateRecorder);
|
||||
|
||||
// Main audio function run by run.ts module.
|
||||
export function initAudioIO(): void {
|
||||
console.log("AUDIO:Starting io streams.")
|
||||
|
||||
if (!ai) {
|
||||
|
||||
// Initialize and start input stream.
|
||||
ai = new portAudio.AudioIO({ inOptions: audioOptions });
|
||||
ai.setEncoding("hex");
|
||||
ai.start();
|
||||
|
||||
// On each data chunk...
|
||||
ai.on('data', (chunk: string) => {
|
||||
|
||||
// If recording, we capture the data.
|
||||
if (record) {
|
||||
console.log('Recording...')
|
||||
audioContainer.input += chunk;
|
||||
}
|
||||
|
||||
// Else, we don't capture and also clear audioContainer.
|
||||
else {
|
||||
if (audioContainer.input.length) {
|
||||
audioContainer.input = "";
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
if (!ao) {
|
||||
|
||||
// Initialize and start input stream.
|
||||
ao = new portAudio.AudioIO({ outOptions: audioOptions });
|
||||
ao.start();
|
||||
|
||||
}
|
||||
|
||||
// Listen to record.
|
||||
console.log("AUDIO:Adding recording listeners.")
|
||||
|
||||
ipcMain.removeAllListeners('start-recording');
|
||||
ipcMain.on('start-recording', () => record = true);
|
||||
|
||||
ipcMain.removeHandler('stop-recording');
|
||||
ipcMain.handle('stop-recording', onRecordingEnd);
|
||||
}
|
||||
|
||||
|
||||
// ---Audio playback--------------------------------------------
|
||||
|
||||
// Split Buffer into an array of len-sized Buffers.
|
||||
function bufSplit(buf: Buffer, len: number): Array<Buffer> {
|
||||
|
|
@ -59,32 +109,6 @@ function bufSplit(buf: Buffer, len: number): Array<Buffer> {
|
|||
return chunks;
|
||||
}
|
||||
|
||||
// Main audio function run by run.ts module.
|
||||
export function initAudioIO(): void {
|
||||
|
||||
if (!ai) {
|
||||
ai = new portAudio.AudioIO({ inOptions: audioOptions });
|
||||
|
||||
// base64 encoding needed for google speech to text.
|
||||
ai.setEncoding(encoding);
|
||||
ai.start();
|
||||
|
||||
ai.on('data', (chunk: string) => {
|
||||
if (record) {
|
||||
console.log('recording...')
|
||||
audioContainer.input += chunk;
|
||||
} else {
|
||||
if (audioContainer.input.length) audioContainer.input = "";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!ao) {
|
||||
ao = new portAudio.AudioIO({ outOptions: audioOptions });
|
||||
ao.start();
|
||||
}
|
||||
}
|
||||
|
||||
// Audio playback.
|
||||
export function play(input: Buffer): void {
|
||||
let i = 0;
|
||||
|
|
@ -128,8 +152,11 @@ export function play(input: Buffer): void {
|
|||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
|
||||
// Get's called on window close.
|
||||
export function stopStream() {
|
||||
console.log("AUDIO:Stopping audio stream.")
|
||||
if(ai != null) {
|
||||
ai.quit();
|
||||
ai = null;
|
||||
|
|
@ -140,3 +167,32 @@ export function stopStream() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// // Returns recorded audio to frontend.
|
||||
// const getAudio = async (_event: any, payload: any) => {
|
||||
|
||||
// return new Promise((resolve, reject) => {
|
||||
|
||||
// // Handle auth response from server.
|
||||
// backgroundMitt.once('auth-res', (res: string) => {
|
||||
|
||||
// if (res == "locked") {
|
||||
// reject(res);
|
||||
// } else {
|
||||
// console.log('Success!');
|
||||
// auth = true;
|
||||
// resolve(res);
|
||||
// }
|
||||
|
||||
// });
|
||||
|
||||
// if (typeof payload !== "string") {
|
||||
// payload = JSON.stringify(payload)
|
||||
// }
|
||||
|
||||
// // Send token to backend
|
||||
// socket.send(payload);
|
||||
|
||||
// });
|
||||
// };
|
||||
|
||||
|
|
|
|||
|
|
@ -2,34 +2,59 @@
|
|||
"use strict";
|
||||
|
||||
import { app } from "electron";
|
||||
import { main } from './run';
|
||||
import { backgroundMitt } from './emitter';
|
||||
import { stopStream } from './audio';
|
||||
import { createWindow } from './window';
|
||||
import { initSession } from './session';
|
||||
import { initAudioIO, stopStream } from './audio';
|
||||
import { backgroundMitt } from '@/modules/emitter';
|
||||
|
||||
let winActive: boolean;
|
||||
let win: boolean;
|
||||
|
||||
// Listen for window creation.
|
||||
backgroundMitt.on('window-active', (state: boolean) => {
|
||||
winActive = state;
|
||||
win = state;
|
||||
});
|
||||
|
||||
// Run when electron app is initialized.
|
||||
async function main() {
|
||||
console.log("MAIN:Initializing Electron App.")
|
||||
|
||||
// Must wait til window is created.
|
||||
await createWindow();
|
||||
|
||||
// Instantiate socket session with crimata-platorm.
|
||||
initSession();
|
||||
|
||||
// Begin audio stream.
|
||||
initAudioIO();
|
||||
|
||||
}
|
||||
|
||||
// Root function of app.
|
||||
export function initApp(dev: boolean): void {
|
||||
|
||||
// On initial startup.
|
||||
app.on("ready", () => {
|
||||
main();
|
||||
main()
|
||||
});
|
||||
|
||||
// Quit when all windows are closed.
|
||||
// Quit app on window closed.
|
||||
app.on("window-all-closed", () => {
|
||||
if (process.platform !== "darwin") {
|
||||
stopStream();
|
||||
app.quit();
|
||||
}
|
||||
console.log("MAIN:Quitting app.")
|
||||
app.quit()
|
||||
});
|
||||
|
||||
// Shutdown audio streams peacefully.
|
||||
app.on("before-quit", () => {
|
||||
stopStream()
|
||||
});
|
||||
|
||||
// When user clicks app icon (re-open)
|
||||
app.on("activate", () => {
|
||||
if (winActive === false) {
|
||||
main();
|
||||
|
||||
if (!win) {
|
||||
createWindow();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Exit cleanly on request from parent process in development mode.
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
import { createWindow } from './window';
|
||||
import agentInterface from './session';
|
||||
import { initAudioIO } from './audio';
|
||||
|
||||
/*
|
||||
* The main function will be run after electron app is ready.
|
||||
*/
|
||||
export async function main() {
|
||||
|
||||
const { initSession } = agentInterface()
|
||||
|
||||
// create main window.
|
||||
await createWindow();
|
||||
|
||||
// Instantiate socket session with crimata-platorm.
|
||||
initSession();
|
||||
|
||||
// Begin audio stream.
|
||||
initAudioIO();
|
||||
|
||||
}
|
||||
|
|
@ -1,3 +1,12 @@
|
|||
/*
|
||||
* Creates a websocket session with Crimata Servers.
|
||||
*
|
||||
* Connects to Servers and attempts token authentication. Will send the result
|
||||
* of the authentication to the window. It will then serve as a communication
|
||||
* interface between the window and the servers. It will automatically try to
|
||||
* reconnect on websocket disconnect.
|
||||
*/
|
||||
|
||||
import { backgroundMitt } from './emitter';
|
||||
import { ipcMain, IpcMainEvent } from "electron";
|
||||
|
||||
|
|
@ -5,13 +14,18 @@ import useWebSockets from "@/modules/ws";
|
|||
|
||||
import { handleAuthMessage, handleStandardMessage, handleProfileMessage, handleAnnotation } from "./handlers";
|
||||
|
||||
// Key for key-based auth.
|
||||
let key: string;
|
||||
|
||||
|
||||
|
||||
|
||||
// Calls appropriate endpoint for a server message.
|
||||
const onServerMessage = (data: string): void => {
|
||||
const onMessage = (data: string) => {
|
||||
const message = JSON.parse(data)
|
||||
|
||||
if (message.key) {
|
||||
backgroundMitt.emit('auth-response', message);
|
||||
if (message.hasOwnProperty("key")) {
|
||||
handleAuthMessage(message)
|
||||
}
|
||||
|
||||
else if (message.content) {
|
||||
|
|
@ -28,27 +42,43 @@ const onServerMessage = (data: string): void => {
|
|||
|
||||
};
|
||||
|
||||
const { createSocket, sendMessage } = useWebSockets(onServerMessage);
|
||||
|
||||
// Handle messages from client.
|
||||
const onClientMessage = (_event: IpcMainEvent, payload: any) {
|
||||
sendMessage(JSON.stringify(payload))
|
||||
// Attempt token authentication onOpen.
|
||||
const onOpen = () => {
|
||||
if (key) {
|
||||
sendMessage({
|
||||
"key": key,
|
||||
"usr": false,
|
||||
"pwd": false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Routes messages to and from Crimata Servers.
|
||||
export default function agentInterface() {
|
||||
|
||||
const initSession = () => {
|
||||
const { createSocket, sendMessage } = useWebSockets(onMessage, onOpen);
|
||||
|
||||
ipcMain.removeAllListeners()
|
||||
// Handle messages from window/client.
|
||||
const onMessageFromWindow = (_event: IpcMainEvent, payload: any) => {
|
||||
console.log("New client message")
|
||||
|
||||
ipcMain.on("client-message", onClientMessage);
|
||||
const success = sendMessage(payload)
|
||||
|
||||
createSocket()
|
||||
if (!success) {
|
||||
console.log("Unable to send message: ", payload)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
initSession
|
||||
}
|
||||
// Call this to initialize session with Crimata servers.
|
||||
export const initSession = (key: string) => {
|
||||
|
||||
// Set the key.
|
||||
key = key;
|
||||
|
||||
// Open socket connection.
|
||||
createSocket()
|
||||
|
||||
// Attach listeners for frontend.
|
||||
ipcMain.removeAllListeners("client-message")
|
||||
ipcMain.on("client-message", onMessageFromWindow);
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -16,7 +16,6 @@ let win: BrowserWindow | null;
|
|||
|
||||
// Called when a NavBar button is pressed.
|
||||
const onNavBar = (_event: any, action: string): void => {
|
||||
console.log("onNavBar")
|
||||
if (win) {
|
||||
if (action === "close") {
|
||||
win.close()
|
||||
|
|
@ -59,18 +58,25 @@ 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);
|
||||
|
||||
// Handle win nav-bar event.
|
||||
ipcMain.removeHandler('nav-bar'); // avoid setting duplicate handlers
|
||||
ipcMain.handle('nav-bar', onNavBar);
|
||||
ipcMain.removeHandler("nav-bar") // avoid setting duplicate handlers
|
||||
ipcMain.handle("nav-bar", onNavBar);
|
||||
|
||||
// Gateway for messages to the frontend.
|
||||
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);
|
||||
}
|
||||
|
|
@ -78,6 +84,7 @@ const onWindowDismount = (): void => {
|
|||
// function used by run.ts to create the main window.
|
||||
export async function createWindow(): Promise<void> {
|
||||
return new Promise((resolve, _reject) => {
|
||||
console.log("BW:Creating browser window. ")
|
||||
|
||||
// avoid creating duplicate windows.
|
||||
if (win) resolve();
|
||||
|
|
@ -122,6 +129,7 @@ export async function createWindow(): Promise<void> {
|
|||
if (win) win.show()
|
||||
})
|
||||
|
||||
// For showing/hiding the splash screen.
|
||||
win.webContents.on('did-finish-load', () => {
|
||||
if (win) win.webContents.send('window-ready', {
|
||||
message: true
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { onMounted, onUnmounted, ref, Ref } from "vue";
|
|||
import useMitt from "@/modules/mitt";
|
||||
import { useIpc } from '@/modules/ipc';
|
||||
import keyboardNameMap from "../keyBoardMaps/keyboardNameMap";
|
||||
import { renderMessage } from '@/modules/message';
|
||||
import { renderMessage, clientMessage } from '@/modules/message';
|
||||
|
||||
|
||||
function showRecIcon () {
|
||||
|
|
@ -34,7 +34,7 @@ function hideRecIcon () {
|
|||
export default function useAudioInputController (typing: Ref) {
|
||||
|
||||
// For sending messages.
|
||||
const { post } = useIpc();
|
||||
const { post, invoke } = useIpc();
|
||||
const { emitter } = useMitt();
|
||||
|
||||
// Keepp track of when we are recording.
|
||||
|
|
@ -49,10 +49,7 @@ export default function useAudioInputController (typing: Ref) {
|
|||
// Start recording on space bar.
|
||||
if (cmd == "SPACE" && !recording.value && !typing.value) {
|
||||
|
||||
post('update-recorder', {
|
||||
isRecording: true,
|
||||
uid: null
|
||||
});
|
||||
post('start-recording', "");
|
||||
|
||||
showRecIcon()
|
||||
recording.value = true;
|
||||
|
|
@ -62,7 +59,7 @@ export default function useAudioInputController (typing: Ref) {
|
|||
|
||||
}
|
||||
|
||||
const onKeyUp = (e: KeyboardEvent) => {
|
||||
const onKeyUp = async (e: KeyboardEvent) => {
|
||||
const cmd = keyboardNameMap[e.keyCode];
|
||||
|
||||
// Stop recording on space up.
|
||||
|
|
@ -72,10 +69,12 @@ export default function useAudioInputController (typing: Ref) {
|
|||
const message = renderMessage("", "", "", "sf")
|
||||
emitter.emit("self-message", message);
|
||||
|
||||
const audio = invoke('update-recorder', {
|
||||
isRecording: false,
|
||||
uid: message.uid
|
||||
});
|
||||
// Stop recording and get audio from recorder.
|
||||
const audio = await invoke('stop-recording', "");
|
||||
|
||||
// Send message to the backend for processing.
|
||||
const clientM = clientMessage("", audio, message.uid);
|
||||
post('client-message', clientM);
|
||||
|
||||
hideRecIcon()
|
||||
recording.value = false;
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<form id="login" @submit.prevent="submit">
|
||||
<form id="login" @submit.prevent="submitForm">
|
||||
|
||||
|
||||
<!-- login title -->
|
||||
|
|
@ -11,24 +11,21 @@
|
|||
<div id="loginBox">
|
||||
<!-- username -->
|
||||
<div class="inputBox">
|
||||
<input class="input" type="text" v-model="email" />
|
||||
<input class="input" type="text" v-model="usr" />
|
||||
<div class="inputModifier">Email</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- password -->
|
||||
<div class="inputBox">
|
||||
<input class="input" type="password" v-model="password" />
|
||||
<input class="input" type="password" v-model="pwd" />
|
||||
<div class="inputModifier">Password</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- submit button; position: fixed -->
|
||||
<button class="submitButton button" type="submitForm">Submit</button>
|
||||
|
||||
<div class="invalid" v-if="invalid">
|
||||
Incorrect Credentials
|
||||
</div>
|
||||
<button class="submitButton button" type="submit">Submit</button>
|
||||
|
||||
</form>
|
||||
|
||||
<!-- back to login button: position: fixed -->
|
||||
|
|
@ -40,8 +37,8 @@
|
|||
import { defineComponent, ref } from "vue";
|
||||
import { useAuth } from "@/modules/auth";
|
||||
import { useIpc } from "@/modules/ipc";
|
||||
import { useRouter } from "vue-router";
|
||||
import useMessages from "@/modules/messages";
|
||||
import { authRequest } from '@/modules/message';
|
||||
|
||||
export default defineComponent({
|
||||
name: "Login",
|
||||
|
|
@ -52,20 +49,18 @@ export default defineComponent({
|
|||
const { setToken } = useAuth();
|
||||
const { resetMessages } = useMessages();
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const form = ref({
|
||||
email: "",
|
||||
password: "",
|
||||
})
|
||||
let usr = ref("");
|
||||
let pwd = ref("");
|
||||
|
||||
// Submit login credentials to the backend.
|
||||
const submitForm = () => {
|
||||
post("auth-message", form)
|
||||
console.log(`Submitting login form: ${usr.value}, ${pwd.value}`)
|
||||
post("client-message", authRequest(false, usr.value, pwd.value))
|
||||
}
|
||||
|
||||
return {
|
||||
form,
|
||||
usr,
|
||||
pwd,
|
||||
submitForm
|
||||
}
|
||||
|
||||
|
|
@ -28,8 +28,7 @@
|
|||
import { defineComponent, ref } from "vue";
|
||||
import { useAuth } from "@/modules/auth";
|
||||
import { useIpc } from "@/modules/ipc";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
import { logoutRequest } from '@/modules/message';
|
||||
|
||||
export default defineComponent({
|
||||
name: "Settings",
|
||||
|
|
@ -38,8 +37,6 @@
|
|||
const toggleSettings = ref(false);
|
||||
|
||||
const { post } = useIpc();
|
||||
const { logout } = useAuth();
|
||||
const router = useRouter();
|
||||
|
||||
// Listen for escape key to close settings.
|
||||
const onEscape = (e: any) => {
|
||||
|
|
@ -57,7 +54,8 @@
|
|||
|
||||
// We ask server to log us out.
|
||||
const onLogout = () => {
|
||||
post("auth-request", "logout")
|
||||
console.log("Submitting logout request.")
|
||||
post("client-message", logoutRequest())
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { RenderMessage, ClientMessage } from "@/types/message/index";
|
||||
import { RenderMessage, ClientMessage, AuthRequest, LogoutRequest } from "@/types/message/index";
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
function getTimeStamp(): number {
|
||||
|
|
@ -27,4 +27,18 @@ export const clientMessage = (text: string, audio: string | boolean, uid: string
|
|||
text,
|
||||
uid
|
||||
}
|
||||
)
|
||||
|
||||
export const authRequest = (key: boolean | string, usr: boolean | string, pwd: boolean | string): AuthRequest => (
|
||||
{
|
||||
key,
|
||||
usr,
|
||||
pwd
|
||||
}
|
||||
)
|
||||
|
||||
export const logoutRequest = (): LogoutRequest => (
|
||||
{
|
||||
logout: true
|
||||
}
|
||||
)
|
||||
|
|
@ -7,40 +7,49 @@ let socket: WebSocket;
|
|||
|
||||
|
||||
// Run every time we want to connect to backend.
|
||||
export default function useWebSockets(receiveCallback: (s: string) => any) {
|
||||
export default function useWebSockets(receiveCallback: (s: string) => any, openCallback: () => any) {
|
||||
|
||||
const sendMessage = (data: string) => {
|
||||
// Returns bool (sucess or fail).
|
||||
const sendMessage = (data: any) => {
|
||||
console.log("WS:Sending message: ", data)
|
||||
|
||||
console.log("Sending message: ", data)
|
||||
|
||||
socket.send(data)
|
||||
if (socket.readyState !== 1) {
|
||||
return false
|
||||
}
|
||||
|
||||
else {
|
||||
socket.send(JSON.stringify(data))
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const onOpen = (event: WebSocket.OpenEvent) => {
|
||||
|
||||
console.log('Connected to Server!');
|
||||
console.log("WS:Connected to WS Server!");
|
||||
|
||||
openCallback()
|
||||
|
||||
}
|
||||
|
||||
const onServerMessage = (event: WebSocket.MessageEvent) => {
|
||||
|
||||
console.log('Message received: ', event);
|
||||
console.log("WS:Message received: ", event.data);
|
||||
|
||||
receiveCallback(event.data.toString())
|
||||
|
||||
}
|
||||
|
||||
const onClose = (event: WebSocket.CloseEvent) => {
|
||||
console.log("Socket closed normally.")
|
||||
console.log("WS:Socket closed normally.")
|
||||
}
|
||||
|
||||
// Reconnect automatically on error.
|
||||
const onError = (event: WebSocket.ErrorEvent) => {
|
||||
console.log('WebSocket error: ', event);
|
||||
console.log("WS:WebSocket error: ", event.message);
|
||||
|
||||
console.log("Reconnecting...")
|
||||
createSocket()
|
||||
console.log("Attempting reconnect in 1s.")
|
||||
setTimeout(createSocket, 1000)
|
||||
}
|
||||
|
||||
const createSocket = () => {
|
||||
|
|
@ -50,9 +59,9 @@ export default function useWebSockets(receiveCallback: (s: string) => any) {
|
|||
socket.addEventListener("open", onOpen)
|
||||
socket.addEventListener("message", onServerMessage)
|
||||
socket.addEventListener("close", onClose)
|
||||
socket.addEventListener("error", createSocket)
|
||||
socket.addEventListener("error", onError)
|
||||
|
||||
console.log("New socket created.")
|
||||
console.log("WS:New socket created.")
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -16,9 +16,14 @@ export interface ClientMessage {
|
|||
uid: string;
|
||||
}
|
||||
|
||||
export interface Creds {
|
||||
email: string;
|
||||
password: string;
|
||||
export interface AuthRequest {
|
||||
key: boolean | string;
|
||||
usr: boolean | string;
|
||||
pwd: boolean | string;
|
||||
}
|
||||
|
||||
export interface LogoutRequest {
|
||||
logout: boolean;
|
||||
}
|
||||
|
||||
// Possible messages from server:
|
||||
|
|
|
|||
|
|
@ -1,197 +0,0 @@
|
|||
<template>
|
||||
<div id="register">
|
||||
<!-- login title -->
|
||||
<div id="registerTitle">
|
||||
<div>Register</div>
|
||||
</div>
|
||||
|
||||
<!-- username and password forms -->
|
||||
<form id="registerBox" @submit.prevent="submit">
|
||||
<!-- username -->
|
||||
<input class="input" type="text" v-model="email" placeholder="email" required/>
|
||||
|
||||
<!-- password -->
|
||||
<input class="input" type="password" v-model="password" placeholder="Password" required/>
|
||||
|
||||
<!-- re-enter passoword -->
|
||||
<input class="input" type="password" v-model="password2" placeholder="Re-enter password" required/>
|
||||
|
||||
<!-- submit button; position: fixed -->
|
||||
<button class="button" type="submit">Submit</button>
|
||||
|
||||
<div v-if="invalidEmail" class="invalid">Invalid Email.</div>
|
||||
<div v-else-if="weakPass" class="invalid">Password must be 8-15 characters long.
|
||||
<br>Password must have at least one:
|
||||
<br>  Upper case letter
|
||||
<br>  Lower case letter
|
||||
<br>  One numeric digit
|
||||
<br>  One special character
|
||||
</div>
|
||||
<div v-else-if="passUnMatch" class="invalid">Passwords dont match.</div>
|
||||
|
||||
</form>
|
||||
|
||||
<!-- back to login button: position: fixed -->
|
||||
<button class="button2" @click.prevent="switchView">Back to login</button>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {
|
||||
defineComponent,
|
||||
ref,
|
||||
} from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { useIpc } from "@/modules/ipc";
|
||||
import { useAuth } from "@/modules/auth";
|
||||
|
||||
interface RegisterPayload {
|
||||
request: string;
|
||||
email: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: "Register",
|
||||
setup() {
|
||||
const router = useRouter();
|
||||
const { invoke } = useIpc();
|
||||
const { setToken } = useAuth();
|
||||
|
||||
const email = ref("");
|
||||
const password = ref("");
|
||||
const password2 = ref("");
|
||||
const invalidEmail = ref(false);
|
||||
const weakPass = ref(false);
|
||||
const passUnMatch = ref(false);
|
||||
|
||||
// emai must be in '@email.com' format
|
||||
const emailReg = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;
|
||||
// password must be 8-15 chars, have one upper, lower, number, and special char
|
||||
const pwReg = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9])(?!.*\s).{8,15}$/;
|
||||
|
||||
// call this function on form submit.
|
||||
const submit = async () => {
|
||||
// reset invalid credentials references.
|
||||
invalidEmail.value = false;
|
||||
weakPass.value = false;
|
||||
passUnMatch.value = false;
|
||||
|
||||
// validate email.
|
||||
if (!emailReg.test(email.value)) {
|
||||
invalidEmail.value = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// validate password strength.
|
||||
if (!pwReg.test(password.value)) {
|
||||
weakPass.value = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// check password match
|
||||
if (password.value !== password2.value) {
|
||||
passUnMatch.value = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const payload: RegisterPayload = {
|
||||
request: "register",
|
||||
email: email.value,
|
||||
password: password.value,
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await invoke('auth-session', payload);
|
||||
setToken(res);
|
||||
router.push({ name: "home" });
|
||||
} catch(e) {
|
||||
console.log('Failed to register.')
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const switchView = () => {
|
||||
router.push({ name: "login" });
|
||||
};
|
||||
|
||||
return {
|
||||
email,
|
||||
password,
|
||||
password2,
|
||||
switchView,
|
||||
submit,
|
||||
invalidEmail,
|
||||
weakPass,
|
||||
passUnMatch,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
#register {
|
||||
width: 350px;
|
||||
height: 500px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #e6e6e6;
|
||||
}
|
||||
|
||||
#registerTitle {
|
||||
min-width: 181px;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#registerBox {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.input {
|
||||
background-color: #B9B9B9;
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 16px;
|
||||
text-decoration: none;
|
||||
margin: 4px 2px;
|
||||
cursor: pointer;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.button {
|
||||
position: fixed;
|
||||
margin-top: 165px;
|
||||
background-color: #58C4FD;
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
text-decoration: none;
|
||||
border-radius: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.button2 {
|
||||
position: fixed;
|
||||
margin-top: 225px;
|
||||
border: none;
|
||||
background-color: #e6e6e6;
|
||||
text-decoration: none;
|
||||
color: #58C4FD;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
font-family: "SF Compact Display";
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
color: #F53737;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1 +1 @@
|
|||
{"w":350,"h":699,"x":649,"y":168}
|
||||
{"w":629,"h":500,"x":1423,"y":657}
|
||||
Loading…
Reference in a new issue