This commit is contained in:
thanawat saiyota 2026-06-16 13:49:26 +07:00
commit b5e0705f79
14 changed files with 262 additions and 103 deletions

View file

@ -39,15 +39,22 @@ import { buildOverviewFromServer } from '$lib/data/recipeService';
import { auth } from '../client/firebase';
import { type RecipeVersion } from '$lib/models/recipe_version.model';
import { goto } from '$app/navigation';
import { socketAlreadySendHeartbeat, socketConnectionOfflineCount } from '../stores/websocketStore';
import {
sharedKey as sharedKey,
socketAlreadySendHeartbeat,
socketConnectionOfflineCount
} from '../stores/websocketStore';
import type { RecipePrice } from '$lib/models/price.model';
import { sendCommandRequest, sendMessage } from './ws_messageSender';
import { auth as authStore } from '../stores/auth';
import { v4 as uuidv4 } from 'uuid';
import { handleSheetResponseFromNoti } from './sheetNotiHandler';
import { env } from '$env/dynamic/public';
import { WebCryptoHelper } from '../utils/crypto';
export const messages = writable<string[]>([]);
type HandshakeAck = { server_public_key: string; status: string };
type WSMessage = { type: string; payload: any };
// MAXIMUM LIMIT = 1814355
@ -133,7 +140,7 @@ const handlers: Record<string, (payload: any) => void> = {
}
}
},
stream_data_end: (p) => {
stream_data_end: async (p) => {
recipeLoading.set(false);
// build overview for recipe from server
@ -156,7 +163,7 @@ const handlers: Record<string, (payload: any) => void> = {
}
// send next chain message
sendMessage({
await sendMessage({
type: 'price',
payload: {
action: {
@ -394,7 +401,7 @@ const handlers: Record<string, (payload: any) => void> = {
currentRecipeVersionsSelector.set(result);
}
},
price: (p) => {
price: async (p) => {
let req_action = p.req_action;
let status = p.status;
let to = p.to;
@ -427,7 +434,7 @@ const handlers: Record<string, (payload: any) => void> = {
current_streaming_instance[request_id] = '';
streamingRawData.set(current_streaming_instance);
sendCommandRequest('sheet', {
await sendCommandRequest('sheet', {
country: current_meta?.country ?? '',
content: saved_product_code_to_get_from_sheet,
param: 'price',
@ -527,24 +534,60 @@ const handlers: Record<string, (payload: any) => void> = {
}
};
export function handleIncomingMessages(raw: string) {
const msg: WSMessage = JSON.parse(raw);
if (msg.type !== 'heartbeat') {
console.log(`[WS MSG] type=${msg.type}`, msg.payload);
}
if (msg == null) {
// error response
addNotification('ERR:No response from server');
function isSecuredAppVersion(version: string | undefined) {
return version?.startsWith('0.0.2') ?? false;
}
export async function handleIncomingMessages(raw: string, clientPrivateKey?: CryptoKey) {
const APP_VERSION = env.PUBLIC_APP_SEMVER;
const parsedMessage = JSON.parse(raw);
const ack: HandshakeAck = parsedMessage;
if (ack != null && ack.status === 'authenticated') {
// has server response
if (!clientPrivateKey) return;
sharedKey.set(await WebCryptoHelper.deriveSharedKey(clientPrivateKey, ack.server_public_key));
addNotification('INFO:Secured Connection');
return;
}
if (isSecuredAppVersion(APP_VERSION) && parsedMessage.ciphertext && parsedMessage.iv) {
// secured message decryption
let sharedKeyStore = get(sharedKey);
if (sharedKeyStore) {
let decrypted_string = await WebCryptoHelper.decryptMessage(
sharedKeyStore,
parsedMessage.ciphertext,
parsedMessage.iv
);
let actual_message: WSMessage = JSON.parse(decrypted_string);
if (actual_message.type !== 'heartbeat') {
console.log(`[WS MSG] type=${actual_message.type}`, actual_message.payload);
}
// raw streaming type
// if (msg.type.startsWith('raw_stream')) {
// // convert
// let sub_type = msg.type.replace('raw_stream_', '');
// msg.payload.sub_type = sub_type;
// msg.type = 'raw_stream';
// }
handlers[actual_message.type]?.(actual_message.payload);
}
} else {
const msg: WSMessage = parsedMessage;
if (msg.type !== 'heartbeat') {
console.log(`[WS MSG] type=${msg.type}`, msg.payload);
}
if (msg == null) {
// error response
addNotification('ERR:No response from server');
return;
}
handlers[msg.type]?.(msg.payload);
// raw streaming type
// if (msg.type.startsWith('raw_stream')) {
// // convert
// let sub_type = msg.type.replace('raw_stream_', '');
// msg.payload.sub_type = sub_type;
// msg.type = 'raw_stream';
// }
handlers[msg.type]?.(msg.payload);
}
}

View file

@ -1,8 +1,11 @@
import { get, writable } from 'svelte/store';
import type { OutMessage } from '../types/outMessage';
import { socketStore } from '../stores/websocketStore';
import { sharedKey, socketStore } from '../stores/websocketStore';
import { addNotification } from '../stores/noti';
import { auth } from '../stores/auth';
import { WebCryptoHelper } from '../utils/crypto';
import * as semver from 'semver';
import { env } from '$env/dynamic/public';
export const queue = writable<string[]>([]);
@ -18,7 +21,7 @@ function getServiceName(cmdReq: CommandRequest) {
}
// Websocket message wrapper for commands like `sheet`, `command`
export function sendCommandRequest(target: CommandRequest, values: any): boolean {
export async function sendCommandRequest(target: CommandRequest, values: any): Promise<boolean> {
let srv_name = getServiceName(target);
let curr_user = get(auth);
@ -31,7 +34,7 @@ export function sendCommandRequest(target: CommandRequest, values: any): boolean
};
}
return sendMessage({
return await sendMessage({
type: target,
payload: {
user_info: user_info ?? {},
@ -41,9 +44,13 @@ export function sendCommandRequest(target: CommandRequest, values: any): boolean
});
}
export function sendMessage(msg: OutMessage, ignore_queue_request: boolean = true): boolean {
export async function sendMessage(
msg: OutMessage,
ignore_queue_request: boolean = true
): Promise<boolean> {
const APP_VERSION = env.PUBLIC_APP_SEMVER;
const socket = get(socketStore);
const data = JSON.stringify(msg);
let data = JSON.stringify(msg);
// console.log('try sending ', data);
@ -64,6 +71,17 @@ export function sendMessage(msg: OutMessage, ignore_queue_request: boolean = tru
return false;
}
// console.log('send v2', APP_VERSION, semver.satisfies(APP_VERSION, '^0.0.2'));
if (semver.satisfies(APP_VERSION, '^0.0.2')) {
console.log('sending secured');
let sharedKeyRes = get(sharedKey);
// do encrypt
if (sharedKeyRes != null)
data = JSON.stringify(await WebCryptoHelper.encryptMessage(sharedKeyRes, data));
}
socket.send(data);
return true;
}