You've already forked obsidian-visualiser
WebSocket API, new ID/encrypt/decrypt algorithm.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { z } from 'zod/v4';
|
||||
import useDatabase from '~/composables/useDatabase';
|
||||
import { campaignMembersTable, campaignTable } from '~/db/schema';
|
||||
import { campaignTable } from '~/db/schema';
|
||||
import { CampaignValidation } from '#shared/campaign.util';
|
||||
import { cryptURI } from '#shared/general.util';
|
||||
|
||||
@@ -26,13 +26,15 @@ export default defineEventHandler(async (e) => {
|
||||
const id = db.transaction((tx) => {
|
||||
const id = tx.insert(campaignTable).values({
|
||||
name: body.data.name,
|
||||
description: body.data.description,
|
||||
public_notes: body.data.public_notes,
|
||||
owner: session.user!.id,
|
||||
dm_notes: body.data.dm_notes,
|
||||
settings: body.data.settings,
|
||||
link: '',
|
||||
}).returning({ id: campaignTable.id }).get().id;
|
||||
|
||||
tx.update(campaignTable).set({ link: cryptURI('campaign', id) }).where(eq(campaignTable.id, id)).run();
|
||||
|
||||
|
||||
return id;
|
||||
});
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ export default defineEventHandler(async (e) => {
|
||||
members: { with: { member: { columns: { username: true, id: true } } }, columns: { id: false, user: false } },
|
||||
characters: { with: { character: { columns: { id: true, name: true, owner: true } } }, columns: { character: false } },
|
||||
owner: { columns: { username: true, id: true } },
|
||||
logs: { columns: { details: true, from: true, timestamp: true, type: true }, orderBy: ({ timestamp }) => timestamp },
|
||||
logs: { columns: { details: true, target: true, timestamp: true, type: true }, orderBy: ({ timestamp }) => timestamp },
|
||||
},
|
||||
where: ({ id: _id }) => eq(_id, parseInt(id, 10)),
|
||||
}).sync();
|
||||
|
||||
@@ -39,7 +39,9 @@ export default defineEventHandler(async (e) => {
|
||||
db.transaction((tx) => {
|
||||
tx.update(campaignTable).set({
|
||||
name: body.data.name,
|
||||
description: body.data.description,
|
||||
public_notes: body.data.public_notes,
|
||||
dm_notes: body.data.dm_notes,
|
||||
settings: body.data.settings,
|
||||
}).where(eq(campaignTable.id, id)).run();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ export default defineEventHandler(async (e) => {
|
||||
columns: { username: true }
|
||||
},
|
||||
campaign: {
|
||||
columns: { character: false, id: false, },
|
||||
columns: { character: false, id: true, },
|
||||
with: {
|
||||
campaign: {
|
||||
columns: { owner: true, },
|
||||
@@ -70,6 +70,8 @@ export default defineEventHandler(async (e) => {
|
||||
owner: character.owner,
|
||||
username: character.user.username,
|
||||
visibility: character.visibility,
|
||||
|
||||
campaign: character.campaign?.id,
|
||||
} as Character;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,30 +1,36 @@
|
||||
const TRIGGER_CHAR = {
|
||||
PING: String.fromCharCode(0x02),
|
||||
PONG: String.fromCharCode(0x03),
|
||||
STATUS: String.fromCharCode(0x04),
|
||||
};
|
||||
import type { SocketMessage } from "#shared/websocket.util";
|
||||
import type { User } from "~/types/auth";
|
||||
|
||||
export default defineWebSocketHandler({
|
||||
message(peer, message) {
|
||||
switch(message.rawData)
|
||||
const data = message.json<SocketMessage>();
|
||||
switch(data.type)
|
||||
{
|
||||
case TRIGGER_CHAR.PING:
|
||||
peer.send(TRIGGER_CHAR.PONG);
|
||||
return;
|
||||
default:
|
||||
case 'PING':
|
||||
peer.send(JSON.stringify({ type: 'PONG' }));
|
||||
return;
|
||||
|
||||
default: return;
|
||||
}
|
||||
},
|
||||
open(peer) {
|
||||
async open(peer) {
|
||||
const id = new URL(peer.request.url).pathname.split('/').slice(-1)[0];
|
||||
if(!id) return peer.close();
|
||||
peer.subscribe(`campaigns/${id}`);
|
||||
peer.publish(`campaigns/${id}`, `${TRIGGER_CHAR.STATUS}`);
|
||||
|
||||
const session = await getUserSession(peer);
|
||||
if(!session ||!session.user) return peer.close();
|
||||
peer.context.user = session.user;
|
||||
|
||||
const topic = `campaigns/${id}`;
|
||||
peer.subscribe(topic);
|
||||
peer.publish(topic, { type: 'user', data: [{ user: (peer.context.user as User).id, status: true }] });
|
||||
peer.send({ type: 'user', data: peer.peers.values().filter(e => e.topics.has(topic)).map(e => ({ user: (e.context.user as User).id, status: true })).toArray() })
|
||||
},
|
||||
close(peer, details) {
|
||||
const id = new URL(peer.request.url).pathname.split('/').slice(-1)[0];
|
||||
if(!id) return peer.close();
|
||||
peer.publish(`campaigns/${id}`, false);
|
||||
|
||||
peer.publish(`campaigns/${id}`, { type: 'user', data: [{ user: (peer.context.user as User).id, status: false }] });
|
||||
peer.unsubscribe(`campaigns/${id}`);
|
||||
}
|
||||
});
|
||||
@@ -4,6 +4,7 @@ import { defu } from 'defu'
|
||||
import { createHooks } from 'hookable'
|
||||
import { useRuntimeConfig } from '#imports'
|
||||
import type { UserSession, UserSessionRequired } from '~/types/auth'
|
||||
import type { CompatEvent } from '~~/shared/websocket.util'
|
||||
|
||||
export interface SessionHooks {
|
||||
/**
|
||||
@@ -11,11 +12,11 @@ export interface SessionHooks {
|
||||
* - Add extra properties to the session
|
||||
* - Throw an error if the session could not be verified (with a database for example)
|
||||
*/
|
||||
fetch: (session: UserSessionRequired, event: H3Event) => void | Promise<void>
|
||||
fetch: (session: UserSessionRequired, event: H3Event | CompatEvent) => void | Promise<void>
|
||||
/**
|
||||
* Called before clearing the session
|
||||
*/
|
||||
clear: (session: UserSession, event: H3Event) => void | Promise<void>
|
||||
clear: (session: UserSession, event: H3Event | CompatEvent) => void | Promise<void>
|
||||
}
|
||||
|
||||
export const sessionHooks = createHooks<SessionHooks>()
|
||||
@@ -25,7 +26,7 @@ export const sessionHooks = createHooks<SessionHooks>()
|
||||
* @param event The Request (h3) event
|
||||
* @returns The user session
|
||||
*/
|
||||
export async function getUserSession(event: H3Event) {
|
||||
export async function getUserSession(event: H3Event | CompatEvent) {
|
||||
const session = await _useSession(event);
|
||||
|
||||
if(!session.data || !session.data.id)
|
||||
@@ -41,7 +42,7 @@ export async function getUserSession(event: H3Event) {
|
||||
* @param data User session data, please only store public information since it can be decoded with API calls
|
||||
* @see https://github.com/atinux/nuxt-auth-utils
|
||||
*/
|
||||
export async function setUserSession(event: H3Event, data: UserSession) {
|
||||
export async function setUserSession(event: H3Event | CompatEvent, data: UserSession) {
|
||||
const session = await _useSession(event)
|
||||
|
||||
await session.update(defu(data, session.data))
|
||||
@@ -54,7 +55,7 @@ export async function setUserSession(event: H3Event, data: UserSession) {
|
||||
* @param event The Request (h3) event
|
||||
* @param data User session data, please only store public information since it can be decoded with API calls
|
||||
*/
|
||||
export async function replaceUserSession(event: H3Event, data: UserSession) {
|
||||
export async function replaceUserSession(event: H3Event | CompatEvent, data: UserSession) {
|
||||
const session = await _useSession(event)
|
||||
|
||||
await session.clear()
|
||||
@@ -68,7 +69,7 @@ export async function replaceUserSession(event: H3Event, data: UserSession) {
|
||||
* @param event The Request (h3) event
|
||||
* @returns true if the session was cleared
|
||||
*/
|
||||
export async function clearUserSession(event: H3Event) {
|
||||
export async function clearUserSession(event: H3Event | CompatEvent) {
|
||||
const session = await _useSession(event)
|
||||
|
||||
await sessionHooks.callHookParallel('clear', session.data, event)
|
||||
@@ -85,7 +86,7 @@ export async function clearUserSession(event: H3Event) {
|
||||
* @param opts.message The message to use for the error (defaults to Unauthorized)
|
||||
* @see https://github.com/atinux/nuxt-auth-utils
|
||||
*/
|
||||
export async function requireUserSession(event: H3Event, opts: { statusCode?: number, message?: string } = {}): Promise<UserSessionRequired> {
|
||||
export async function requireUserSession(event: H3Event | CompatEvent, opts: { statusCode?: number, message?: string } = {}): Promise<UserSessionRequired> {
|
||||
const userSession = await getUserSession(event)
|
||||
|
||||
if (!userSession.user) {
|
||||
@@ -100,9 +101,9 @@ export async function requireUserSession(event: H3Event, opts: { statusCode?: nu
|
||||
|
||||
let sessionConfig: SessionConfig
|
||||
|
||||
function _useSession(event: H3Event) {
|
||||
if (!sessionConfig) {
|
||||
const runtimeConfig = useRuntimeConfig(event)
|
||||
function _useSession(event: H3Event | CompatEvent) {
|
||||
if (!sessionConfig && '__is_event__' in event) {
|
||||
const runtimeConfig = useRuntimeConfig(event);
|
||||
|
||||
sessionConfig = runtimeConfig.session;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user