feature: add secured message

- encrypt/decrypt every message (require ^0.0.2)

Signed-off-by: pakintada@gmail.com <Pakin>
This commit is contained in:
pakintada@gmail.com 2026-06-16 10:34:29 +07:00
parent 4ca8b3b270
commit 2a0841a798
14 changed files with 314 additions and 147 deletions

View file

@ -7,16 +7,20 @@ import { auth } from '../client/firebase';
import { auth as authStore } from '$lib/core/stores/auth';
import { addNotification } from './noti';
import { permission } from './permissions';
import { WebCryptoHelper } from '../utils/crypto';
let socket: WebSocket | null = null;
let reconnectTimeout: any;
let socketCheck: any;
let sendAuthInfoInterval: any;
const ENABLE_WS_DEBUG: boolean = false;
export const socketConnectionOfflineCount = writable<number>(0);
export const socketAlreadySendHeartbeat = writable<number>(0);
export const socketStore = writable<WebSocket | null>(null);
export const sharedKey = writable<CryptoKey | null>(null);
export function waitForOpenSocket(timeoutMs = 8000): Promise<WebSocket | null> {
const currentSocket = get(socketStore);
if (currentSocket?.readyState === WebSocket.OPEN) {
@ -49,7 +53,7 @@ export function waitForOpenSocket(timeoutMs = 8000): Promise<WebSocket | null> {
});
}
export function connectToWebsocket(id_token?: string) {
export async function connectToWebsocket(id_token?: string) {
if (browser) {
// console.log('connecting to ', env.PUBLIC_WSS);
try {
@ -57,12 +61,12 @@ export function connectToWebsocket(id_token?: string) {
return;
}
let productionMode = env.PUBLIC_WSS.startsWith('wss');
let ws_url = productionMode ? `${env.PUBLIC_WSS}?token=${id_token}` : `${env.PUBLIC_WSS}`;
let ws_url = env.PUBLIC_WSS;
socket = new WebSocket(ws_url);
sharedKey.set(null);
const { privateKey, publicKeyBase64 } = await WebCryptoHelper.generateKeyPair();
socket.addEventListener('open', () => {
socket.addEventListener('open', async () => {
socketStore.set(socket);
addNotification('INFO:Connected!');
@ -74,29 +78,40 @@ export function connectToWebsocket(id_token?: string) {
let auth_data = get(authStore);
let perms = get(permission);
// Debug: check if auth_data has uid
console.log('[WS Auth] Sending auth with:', {
uid: auth_data?.uid,
name: auth_data?.displayName,
email: auth_data?.email
});
socket.send(
JSON.stringify({
token: id_token ?? '',
client_public_key: publicKeyBase64
})
);
sendMessage({
type: 'auth',
payload: {
user: {
uid: auth_data?.uid ?? '',
name: auth_data?.displayName ?? '',
email: auth_data?.email ?? '',
permissions: perms.join(',')
}
sendAuthInfoInterval = setInterval(async () => {
if (get(sharedKey)) {
// Debug: check if auth_data has uid
console.log('[WS Auth] Sending auth info with:', {
uid: auth_data?.uid,
name: auth_data?.displayName,
email: auth_data?.email
});
await sendMessage({
type: 'auth',
payload: {
user: {
uid: auth_data?.uid ?? '',
name: auth_data?.displayName ?? '',
email: auth_data?.email ?? '',
permissions: perms.join(',')
}
}
});
clearInterval(sendAuthInfoInterval);
}
});
}, 3000);
}
console.log(socket);
// heartbeat 10s
socketCheck = setInterval(() => {
socketCheck = setInterval(async () => {
if (get(socketAlreadySendHeartbeat) > 0) {
let heartbeat_may_offline_count = get(socketConnectionOfflineCount);
@ -108,13 +123,13 @@ export function connectToWebsocket(id_token?: string) {
socketConnectionOfflineCount.set(0);
socketAlreadySendHeartbeat.set(0);
connectToWebsocket(id_token);
await connectToWebsocket(id_token);
return;
}
if (socket != null) {
sendMessage({
await sendMessage({
type: 'heartbeat',
payload: {}
});
@ -130,18 +145,19 @@ export function connectToWebsocket(id_token?: string) {
if (auth.currentUser && socket == null) {
console.log('try reconnect websocket ...');
// retry again
reconnectTimeout = setTimeout(() => {
connectToWebsocket(id_token);
reconnectTimeout = setTimeout(async () => {
await connectToWebsocket(id_token);
}, 5000);
}
});
socket.addEventListener('message', (event) => {
handleIncomingMessages(event.data);
socket.addEventListener('message', async (event) => {
await handleIncomingMessages(event.data, privateKey);
});
socket.addEventListener('close', () => {
socketStore.set(null);
sharedKey.set(null);
socket = null;
clearInterval(socketCheck);
@ -149,13 +165,14 @@ export function connectToWebsocket(id_token?: string) {
if (auth.currentUser && !socket) {
console.log('try reconnect websocket ...');
// retry again
reconnectTimeout = setTimeout(() => connectToWebsocket(id_token), 5000);
reconnectTimeout = setTimeout(async () => await connectToWebsocket(id_token), 5000);
}
});
socket.addEventListener('error', (e) => {
// console.log('WebSocket error: ', e);
socketStore.set(null);
sharedKey.set(null);
});
} catch (socket_error: any) {
if (ENABLE_WS_DEBUG) {