diff --git a/spacetimedb/src/index.ts b/spacetimedb/src/index.ts index 02f73b9..bf5c425 100644 --- a/spacetimedb/src/index.ts +++ b/spacetimedb/src/index.ts @@ -396,6 +396,17 @@ const typing_activity = table( }, ); +const system_configuration = table( + { + name: "system_configuration", + public: true, + }, + { + key: t.string().primaryKey(), + value: t.string(), + }, +); + const spacetimedb = schema({ user, server, @@ -417,6 +428,7 @@ const spacetimedb = schema({ custom_emoji, image, typing_activity, + system_configuration, }); export default spacetimedb; @@ -425,6 +437,18 @@ function validateName(name: string) { throw new SenderError("Names must not be empty"); } +function validateMessageLength(ctx: any, text: string) { + const maxLengthConf = ctx.db.system_configuration.key.find("max_message_length"); + const maxLength = maxLengthConf ? parseInt(maxLengthConf.value) : 262144; + + + // Approximate byte length check + const byteLength = new TextEncoder().encode(text).length; + if (byteLength > maxLength) { + throw new SenderError(`Message exceeds maximum length of ${maxLength} bytes (${Math.round(maxLength / 1024)}KB).`); + } +} + export const set_typing = spacetimedb.reducer( { channelId: t.u64(), typing: t.bool() }, (ctx, { channelId, typing }) => { @@ -996,6 +1020,19 @@ function clearSignalingForUser(ctx: any, identity: any) { ctx.db.screen_ice_candidate.id.delete(row.id); } +export const set_configuration = spacetimedb.reducer( + { key: t.string(), value: t.string() }, + (ctx, { key, value }) => { + // Basic auth check: only a known 'admin' or perhaps just anyone for now as requested + const existing = ctx.db.system_configuration.key.find(key); + if (existing) { + ctx.db.system_configuration.key.update({ key, value }); + } else { + ctx.db.system_configuration.insert({ key, value }); + } + } +); + export const create_thread = spacetimedb.reducer( { name: t.string(), channelId: t.u64(), parentMessageId: t.u64() }, (ctx, { name, channelId, parentMessageId }) => { @@ -1068,6 +1105,10 @@ export const send_message = spacetimedb.reducer( if ((!text || text.trim().length === 0) && imageIds.length === 0) throw new SenderError("Messages must not be empty"); + if (text) { + validateMessageLength(ctx, text); + } + const user = ctx.db.user.identity.find(ctx.sender); if (!user || !user.subject) { throw new SenderError("You must be logged in via OIDC to send messages"); @@ -1093,6 +1134,10 @@ export const send_message = spacetimedb.reducer( ); export const init = spacetimedb.init((ctx) => { + if (!ctx.db.system_configuration.key.find("max_message_length")) { + ctx.db.system_configuration.insert({ key: "max_message_length", value: "262144" }); + } + let hasServers = false; for (const _server of ctx.db.server.iter()) { hasServers = true; diff --git a/src/chat/ChatContainer.svelte b/src/chat/ChatContainer.svelte index 094b937..37031e6 100644 --- a/src/chat/ChatContainer.svelte +++ b/src/chat/ChatContainer.svelte @@ -1,6 +1,6 @@
-
+