upgrading auth functionality
This commit is contained in:
parent
4b3023fd4c
commit
9bf7496899
12 changed files with 92 additions and 362 deletions
40
src/App.vue
40
src/App.vue
|
|
@ -15,8 +15,9 @@
|
|||
/>
|
||||
</span>
|
||||
|
||||
<!-- Windows -->
|
||||
<router-view/>
|
||||
<!-- Main Pages -->
|
||||
<Messenger v-if="auth"/>
|
||||
<Login v-else />
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -26,7 +27,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, onUnmounted, ref } from 'vue';
|
||||
import { defineComponent, onMounted, onUnmounted, ref } from "vue";
|
||||
import { useIpc } from "@/modules/ipc";
|
||||
import Splash from "@/components/splash.vue"
|
||||
|
||||
|
|
@ -34,33 +35,48 @@ export default defineComponent({
|
|||
components: { Splash },
|
||||
|
||||
setup() {
|
||||
|
||||
|
||||
// Show spash screen til true.
|
||||
const ready = ref(false);
|
||||
|
||||
const { invoke } = useIpc();
|
||||
// Whether user is logged in.
|
||||
let auth = ref(false);
|
||||
|
||||
// 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) {
|
||||
auth.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Post navbar action to backend.
|
||||
const callNavbar = (action: string) => {
|
||||
invoke('nav-bar', action);
|
||||
post('nav-bar', action);
|
||||
}
|
||||
|
||||
const onWindowReady = (_event: any, _payload: any) => {
|
||||
ready.value = true;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.ipcRenderer.on("window-ready", onWindowReady);
|
||||
window.ipcRenderer.on("auth-response", onAuthResponse)
|
||||
|
||||
|
||||
window.ipcRenderer.on("window-ready", () => ready.value = true);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.ipcRenderer.removeAllListeners("window-ready")
|
||||
window.ipcRenderer.removeAllListeners("auth-response")
|
||||
})
|
||||
|
||||
return {
|
||||
callNavbar,
|
||||
ready
|
||||
ready,
|
||||
auth,
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,19 +2,24 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
import { sendAudio } from './session'
|
||||
import { ipcMain } from "electron";
|
||||
import { backgroundMitt } from './emitter';
|
||||
|
||||
const portAudio = require('naudiodon');
|
||||
|
||||
// Audio in and out stream objects.
|
||||
let ai: typeof portAudio.AudioIO | null = null;
|
||||
let ao: typeof portAudio.AudioIO | null = null;
|
||||
|
||||
// Whether activly recording.
|
||||
let record = false;
|
||||
|
||||
const audioContainer = {
|
||||
input: '',
|
||||
}
|
||||
|
||||
const encoding = "hex";
|
||||
|
||||
const audioOptions = {
|
||||
channelCount: 1,
|
||||
sampleFormat: 16,
|
||||
|
|
@ -24,14 +29,15 @@ const audioOptions = {
|
|||
}
|
||||
|
||||
// callback run on space bar key up and down.
|
||||
const updateRecorder = (_event, payload: {
|
||||
isRecording: boolean;
|
||||
uid: string | null;
|
||||
const updateRecorder = (_event, payload: { isRecording: boolean; uid: string | null;
|
||||
|
||||
}): void => {
|
||||
|
||||
record = payload.isRecording;
|
||||
if (!record) {
|
||||
if (payload.uid) sendAudio(audioContainer.input, payload.uid);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// listen for space key up/down event.
|
||||
|
|
@ -53,7 +59,7 @@ function bufSplit(buf: Buffer, len: number): Array<Buffer> {
|
|||
return chunks;
|
||||
}
|
||||
|
||||
// main audio function run by run.ts module.
|
||||
// Main audio function run by run.ts module.
|
||||
export function initAudioIO(): void {
|
||||
|
||||
if (!ai) {
|
||||
|
|
@ -79,7 +85,7 @@ export function initAudioIO(): void {
|
|||
}
|
||||
}
|
||||
|
||||
// play audio buffers.
|
||||
// Audio playback.
|
||||
export function play(input: Buffer): void {
|
||||
let i = 0;
|
||||
|
||||
|
|
@ -122,6 +128,7 @@ export function play(input: Buffer): void {
|
|||
}
|
||||
}
|
||||
|
||||
// Get's called on window close.
|
||||
export function stopStream() {
|
||||
if(ai != null) {
|
||||
ai.quit();
|
||||
|
|
|
|||
|
|
@ -1,48 +1,24 @@
|
|||
import { backgroundMitt } from './emitter';
|
||||
import { backgroundMitt } from "./emitter";
|
||||
import { renderMessage } from "@/modules/message";
|
||||
import { Profile, StandardMessage, Annotation } from "@/types/message/index";
|
||||
import { play } from "./audio";
|
||||
|
||||
// Attempt an authenticaion, either with Token or with Creds.
|
||||
const onAuthRequest = async (e: any, payload: string | Creds) => {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
console.log('Authenticating...');
|
||||
|
||||
// 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);
|
||||
|
||||
export const handleAuthMessage = (message: string) => {
|
||||
backgroundMitt.emit('ipc-renderer', {
|
||||
endpoint: 'auth-response',
|
||||
message: message
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const handleAuthMessage = (message: string) => {
|
||||
backgroundMitt.emit('auth-res', message);
|
||||
}
|
||||
|
||||
const handleProfileMessage = (message: Profile) => {
|
||||
export const handleProfileMessage = (message: Profile) => {
|
||||
backgroundMitt.emit('ipc-renderer', {
|
||||
endpoint: 'update-profile',
|
||||
message: message
|
||||
});
|
||||
}
|
||||
|
||||
const handleStandardMessage = (m: StandardMessage) => {
|
||||
export const handleStandardMessage = (m: StandardMessage) => {
|
||||
|
||||
// Create a render message object.
|
||||
const message = renderMessage(
|
||||
|
|
@ -61,7 +37,7 @@ const handleStandardMessage = (m: StandardMessage) => {
|
|||
});
|
||||
}
|
||||
|
||||
const handleAnnotationMessage = (message: Annotation) => {
|
||||
export const handleAnnotation = (message: Annotation) => {
|
||||
backgroundMitt.emit('ipc-renderer', {
|
||||
endpoint: 'render-message',
|
||||
message: message
|
||||
|
|
|
|||
|
|
@ -1,27 +1,21 @@
|
|||
"use strict";
|
||||
|
||||
import { createWindow } from './window';
|
||||
import useWebSockets from './session';
|
||||
import agentInterface from './session';
|
||||
import { initAudioIO } from './audio';
|
||||
|
||||
let socket = false;
|
||||
|
||||
/*
|
||||
* The main function will be run after electron app is ready.
|
||||
*/
|
||||
export async function main() {
|
||||
|
||||
const { initSession } = useWebSockets()
|
||||
const { initSession } = agentInterface()
|
||||
|
||||
// create main window.
|
||||
await createWindow();
|
||||
|
||||
// Instantiate socket session with crimata-platorm.
|
||||
if (!socket) {
|
||||
initSocketSession();
|
||||
}
|
||||
|
||||
socket = true;
|
||||
initSession();
|
||||
|
||||
// Begin audio stream.
|
||||
initAudioIO();
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
import { backgroundMitt } from './emitter';
|
||||
import { ipcMain, IpcMainEvent } from "electron";
|
||||
|
||||
import useWebSockets from "@/modules/ws";
|
||||
|
||||
import { handleAuthMessage, handleStandardMessage, handleProfileMessage, handleAnnotation } from "./handlers";
|
||||
|
||||
|
||||
// Handle messages from server.
|
||||
// Calls appropriate endpoint for a server message.
|
||||
const onServerMessage = (data: string): void => {
|
||||
const message = JSON.parse(data)
|
||||
|
||||
if (message.key) {
|
||||
handleAuthMessage(message)
|
||||
backgroundMitt.emit('auth-response', message);
|
||||
}
|
||||
|
||||
else if (message.content) {
|
||||
|
|
@ -20,27 +23,26 @@ const onServerMessage = (data: string): void => {
|
|||
}
|
||||
|
||||
else {
|
||||
handleAnnotationMessage(message)
|
||||
handleAnnotation(message)
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const { createSocket, sendMessage } = useWebSockets(onServerMessage);
|
||||
|
||||
// Handle messages from client.
|
||||
const onClientMessage = (_event: IpcMainEvent, payload: any) {
|
||||
sendMessage(JSON.stringify(payload))
|
||||
}
|
||||
|
||||
// Routes messages to and from Crimata Servers.
|
||||
export default function agentInterface() {
|
||||
|
||||
const { createSocket, sendMessage } = useWebSockets(onServerMessage)
|
||||
|
||||
const initSession = () => {
|
||||
|
||||
ipcMain.removeAllListeners()
|
||||
ipcMain.removeHandler('auth-session');
|
||||
|
||||
ipcMain.handle('auth-request', onAuthRequest);
|
||||
ipcMain.on('client-message', onClientMessage);
|
||||
ipcMain.on("client-message", onClientMessage);
|
||||
|
||||
createSocket()
|
||||
}
|
||||
|
|
@ -49,117 +51,4 @@ export default function agentInterface() {
|
|||
initSession
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Attempt an authenticaion, either with Token or with Creds.
|
||||
const onAuthRequest = async (e: any, payload: string | Creds) => {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
console.log('Authenticating...');
|
||||
|
||||
// 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);
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const handleAuthMessage = (message: string) => {
|
||||
backgroundMitt.emit('auth-res', message);
|
||||
}
|
||||
|
||||
const handleProfileMessage = (message: Profile) => {
|
||||
backgroundMitt.emit('ipc-renderer', {
|
||||
endpoint: 'update-profile',
|
||||
message: message
|
||||
});
|
||||
}
|
||||
|
||||
const handleStandardMessage = (m: StandardMessage) => {
|
||||
|
||||
// Create a render message object.
|
||||
const message = renderMessage(
|
||||
m.content.text, m.content.audio, m.context, m.modifier);
|
||||
|
||||
// Play audio if any.
|
||||
if (message.content.audio) {
|
||||
const audioBytes = Buffer.from(m.content.audio as string, 'hex');
|
||||
m.content.audio = true;
|
||||
play(audioBytes);
|
||||
}
|
||||
|
||||
backgroundMitt.emit('ipc-renderer', {
|
||||
endpoint: 'render-message',
|
||||
message: message
|
||||
});
|
||||
}
|
||||
|
||||
const handleAnnotationMessage = (message: Annotation) => {
|
||||
backgroundMitt.emit('ipc-renderer', {
|
||||
endpoint: 'render-message',
|
||||
message: message
|
||||
});
|
||||
}
|
||||
|
||||
const onMessage = (messageStr: string): void => {
|
||||
|
||||
// Auth messages are strings.
|
||||
if (!auth) {
|
||||
handleAuthMessage(messageStr)
|
||||
return
|
||||
}
|
||||
|
||||
const message = JSON.parse(messageStr)
|
||||
console.log("New message:")
|
||||
console.log(message)
|
||||
|
||||
if (message.content) {
|
||||
handleStandardMessage(message)
|
||||
}
|
||||
|
||||
else if (message.first) {
|
||||
handleProfileMessage(message)
|
||||
}
|
||||
|
||||
else {
|
||||
handleAnnotationMessage(message)
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const onClientMessage = (e: any, payload: ClientMessage): void => {
|
||||
console.log('sending message');
|
||||
socket.send(JSON.stringify(payload));
|
||||
}
|
||||
|
|
@ -72,7 +72,7 @@ export default function useAudioInputController (typing: Ref) {
|
|||
const message = renderMessage("", "", "", "sf")
|
||||
emitter.emit("self-message", message);
|
||||
|
||||
post('update-recorder', {
|
||||
const audio = invoke('update-recorder', {
|
||||
isRecording: false,
|
||||
uid: message.uid
|
||||
});
|
||||
|
|
|
|||
|
|
@ -55,19 +55,17 @@
|
|||
window.addEventListener("keydown", onEscape);
|
||||
}
|
||||
|
||||
// When user clicks logout button in settings.
|
||||
// We ask server to log us out.
|
||||
const onLogout = () => {
|
||||
logout();
|
||||
router.push({ name: "login" });
|
||||
post("logout", "")
|
||||
}
|
||||
post("auth-request", "logout")
|
||||
}
|
||||
|
||||
return {
|
||||
onActive,
|
||||
toggleSettings,
|
||||
onLogout
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// src/main.ts
|
||||
|
||||
import App from "./App.vue";
|
||||
import router from "./router";
|
||||
|
||||
import mitt from "mitt";
|
||||
import { createApp } from "vue";
|
||||
|
|
@ -12,6 +11,5 @@ const emitter = mitt();
|
|||
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(router)
|
||||
app.provide("mitt", emitter)
|
||||
app.mount("#app");
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ if (token) {
|
|||
window.localStorage.setItem(AUTH_KEY, token);
|
||||
}
|
||||
|
||||
// Load key and invoke onAuthSession to try key-login.
|
||||
// Token authentication.
|
||||
const authToken = async () => {
|
||||
console.log("Calling auth token!!")
|
||||
const { invoke } = useIpc();
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ let socket: WebSocket;
|
|||
|
||||
|
||||
// Run every time we want to connect to backend.
|
||||
export default function useWebSockets(receiveCallback: (s: Buffer) => any) {
|
||||
export default function useWebSockets(receiveCallback: (s: string) => any) {
|
||||
|
||||
const sendMessage = (data: string) => {
|
||||
|
||||
|
|
@ -27,14 +27,15 @@ export default function useWebSockets(receiveCallback: (s: Buffer) => any) {
|
|||
|
||||
console.log('Message received: ', event);
|
||||
|
||||
receiveCallback(event.data)
|
||||
receiveCallback(event.data.toString())
|
||||
|
||||
}
|
||||
|
||||
const onClose = (event: WebSocket.CloseEvent) => {
|
||||
console.log("socket closed normally.")
|
||||
console.log("Socket closed normally.")
|
||||
}
|
||||
|
||||
// Reconnect automatically on error.
|
||||
const onError = (event: WebSocket.ErrorEvent) => {
|
||||
console.log('WebSocket error: ', event);
|
||||
|
||||
|
|
@ -55,76 +56,8 @@ export default function useWebSockets(receiveCallback: (s: Buffer) => any) {
|
|||
}
|
||||
|
||||
return {
|
||||
createSocket
|
||||
createSocket,
|
||||
sendMessage
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Close existing sockets.
|
||||
if (socket) {
|
||||
socket.removeAllListeners();
|
||||
socket.terminate();
|
||||
socket.close();
|
||||
success = false;
|
||||
}
|
||||
|
||||
// Init new socket.
|
||||
socket = new WebSocket(`ws://127.0.0.1:8760`);
|
||||
socket.binaryType = 'arraybuffer';
|
||||
|
||||
// Handle requests for authentication (promise).
|
||||
ipcMain.removeHandler('auth-session'); // avoid setting duplicate handlers
|
||||
ipcMain.handle('auth-session', onAuthSession);
|
||||
|
||||
// handle user message event
|
||||
ipcMain.removeAllListeners('client-message');
|
||||
ipcMain.on('client-message', onClientMessage);
|
||||
|
||||
// handle renderer logout event
|
||||
ipcMain.removeAllListeners('logout');
|
||||
ipcMain.on('logout', (_event, _payload: string) => restart());
|
||||
|
||||
// Connect to the backend.
|
||||
socket.on('open', () => {
|
||||
console.log('Connected to Crimata Servers.');
|
||||
|
||||
// Try to authenticate token right away.
|
||||
backgroundMitt.emit('ipc-renderer', {
|
||||
endpoint: 'auth',
|
||||
message: null
|
||||
});
|
||||
|
||||
success = true;
|
||||
|
||||
});
|
||||
|
||||
// Error handling.
|
||||
socket.on('error', (_e) => {
|
||||
|
||||
console.log('ERROR: Failed to connect.');
|
||||
socket.removeAllListeners();
|
||||
socket.close();
|
||||
|
||||
setTimeout(() => {
|
||||
if (!success) {
|
||||
console.log('Reconnecting...');
|
||||
initSession();
|
||||
}
|
||||
}, 3000); // reconnect timeout
|
||||
|
||||
});
|
||||
|
||||
socket.on('close', () => {
|
||||
console.log('Connection droped! Restarting...');
|
||||
restart();
|
||||
});
|
||||
|
||||
socket.on("message", onMessage);
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
import {
|
||||
createRouter,
|
||||
createWebHistory,
|
||||
createWebHashHistory,
|
||||
RouteRecordRaw
|
||||
} from "vue-router";
|
||||
import Home from "@/views/messenger.vue";
|
||||
import { useAuth } from '@/modules/auth';
|
||||
|
||||
// Define the routes (/*) for the app here.
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "/",
|
||||
name: "home",
|
||||
component: Home,
|
||||
meta: { requiresAuth: true },
|
||||
},
|
||||
{
|
||||
path: "/login",
|
||||
name: "login",
|
||||
component: () => import("@/views/login.vue"),
|
||||
meta: { requiresAuth: false },
|
||||
},
|
||||
{
|
||||
path: "/register",
|
||||
name: "register",
|
||||
component: () => import("@/views/register.vue"),
|
||||
meta: { requiresAuth: false },
|
||||
},
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
history: process.env.IS_ELECTRON ? createWebHashHistory() : createWebHistory(process.env.BASE_URL),
|
||||
routes
|
||||
});
|
||||
|
||||
// route auth check
|
||||
router.beforeEach((to, from, next) => {
|
||||
const { accessToken } = useAuth();
|
||||
|
||||
// Not logged into a guarded route?
|
||||
if (to.meta.requiresAuth && !accessToken.value) {
|
||||
next({ name: 'login' })
|
||||
}
|
||||
|
||||
// Logged in for an auth route
|
||||
else if ((to.name == 'login' || to.name == 'register') && accessToken.value){
|
||||
next({ name: 'home' });
|
||||
}
|
||||
|
||||
// Carry On...
|
||||
else next();
|
||||
})
|
||||
|
||||
export default router;
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
</div>
|
||||
|
||||
<!-- submit button; position: fixed -->
|
||||
<button class="submitButton button" type="submit">Submit</button>
|
||||
<button class="submitButton button" type="submitForm">Submit</button>
|
||||
|
||||
<div class="invalid" v-if="invalid">
|
||||
Incorrect Credentials
|
||||
|
|
@ -48,57 +48,31 @@ export default defineComponent({
|
|||
|
||||
setup() {
|
||||
|
||||
const { post } = useIpc();
|
||||
const { setToken } = useAuth();
|
||||
const { resetMessages } = useMessages();
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const email = ref("");
|
||||
const password = ref("");
|
||||
const invalid = ref(false);
|
||||
const form = ref({
|
||||
email: "",
|
||||
password: "",
|
||||
})
|
||||
|
||||
const { invoke } = useIpc();
|
||||
|
||||
const submit = async () => {
|
||||
|
||||
const payload = {
|
||||
request: "login",
|
||||
email: email.value,
|
||||
password: password.value
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await invoke('auth-session', payload);
|
||||
|
||||
// On login without token, we clear localStorage and messages.
|
||||
window.localStorage.clear();
|
||||
resetMessages();
|
||||
|
||||
setToken(response);
|
||||
invalid.value = false;
|
||||
router.push({ name: "home" });
|
||||
}
|
||||
|
||||
catch(e) {
|
||||
invalid.value = true;
|
||||
console.log('Error loging in.');
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const switchView = () => {
|
||||
router.push({ name: "register" });
|
||||
};
|
||||
// Submit login credentials to the backend.
|
||||
const submitForm = () => {
|
||||
post("auth-message", form)
|
||||
}
|
||||
|
||||
return {
|
||||
submit,
|
||||
email,
|
||||
password,
|
||||
switchView,
|
||||
invalid
|
||||
form,
|
||||
submitForm
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
|||
Loading…
Reference in a new issue