feat: support leaving chat, chat message toasts for non-guests IF logged into chat
Some checks are pending
Check / check (push) Waiting to run

This commit is contained in:
ThaUnknown 2025-06-16 21:40:14 +02:00
parent 361ca69f42
commit 56a1cfbc98
No known key found for this signature in database
5 changed files with 43 additions and 17 deletions

View file

@ -1,6 +1,6 @@
{
"name": "ui",
"version": "6.3.66",
"version": "6.3.67",
"license": "BUSL-1.1",
"private": true,
"packageManager": "pnpm@9.14.4",

View file

@ -1,5 +1,5 @@
<script lang='ts'>
import DoorOpen from 'lucide-svelte/icons/door-open'
import SendHorizontal from 'lucide-svelte/icons/send-horizontal'
import { Button } from '../button'
@ -7,7 +7,9 @@
import type MessageClient from '$lib/modules/irc'
import { goto } from '$app/navigation'
import { Textarea } from '$lib/components/ui/textarea'
import { prevAgreed } from '$lib/modules/irc'
export let client: MessageClient
@ -37,13 +39,22 @@
$: users = client.users
$: processedUsers = Object.values($users)
function quit () {
$prevAgreed = false
client.destroy()
goto('/app/home')
}
</script>
<div class='flex flex-col w-full relative px-md-4 h-full overflow-hidden'>
<div class='flex md:flex-row flex-col-reverse w-full h-full pt-4'>
<div class='flex flex-col justify-end overflow-hidden flex-grow px-4 md:pb-4'>
<Messages messages={client.messages} />
<div class='flex mt-4'>
<div class='flex mt-4 gap-2'>
<Button on:click={quit} size='icon' class='border-0 shrink-0' variant='outline'>
<DoorOpen size={18} />
</Button>
<Textarea
bind:value={message}
class='h-auto px-3 w-full flex-grow-1 resize-none min-h-0 border-0 bg-background select:bg-accent select:text-accent-foreground'
@ -51,7 +62,7 @@
autocomplete='off'
maxlength={256}
placeholder='Message' on:keydown={checkInput} on:input={updateRows} />
<Button on:click={sendMessage} size='icon' class='mt-auto ml-2 border-0' variant='outline'>
<Button on:click={sendMessage} size='icon' class='mt-auto border-0' variant='outline'>
<SendHorizontal size={18} />
</Button>
</div>

View file

@ -1,7 +1,7 @@
import { arr2hex, arr2text, bin2hex, hex2arr, hex2bin, text2arr } from 'uint8-util'
// could use a simple XOR encryption/decryption but meh, some1 could easily brute force it
const key = new Uint8Array([104, 97, 121, 97, 115, 101, 45, 111, 118, 101, 114, 45, 97, 108, 108, 45, 251, 249, 0, 204, 242, 221, 119, 44, 147, 27, 83, 227, 225, 179, 149, 80, 70, 163, 58, 97, 201, 1, 10, 33, 78, 172, 195, 239, 171, 119, 51, 199, 127, 248, 221, 31, 90, 114, 200, 255, 252, 158, 158, 57, 245, 153, 44, 126, 130, 232, 230, 192, 0, 223, 204, 137, 211, 115, 33, 42, 68, 227, 65, 161, 17, 116, 138, 195, 51, 51, 181, 183, 124, 119, 161, 74, 202, 21, 182, 195, 134, 198, 191, 182, 223, 205, 60, 175, 207, 223, 232, 94, 133, 70, 10, 127, 100, 170, 109, 22])
const key = new Uint8Array([104, 97, 121, 97, 115, 101, 45, 111, 118, 101, 114, 45, 97, 108, 108, 45, 251, 249, 0, 204, 242, 221, 119, 44, 147, 27, 83, 227, 225, 179, 149, 80, 70, 163, 58, 97, 201, 1, 10, 33, 78, 172, 195, 239, 171, 119, 51, 199, 127, 248, 221, 31, 90, 114, 200, 255, 252, 158, 158, 57, 245, 153, 44, 126, 130, 232, 230, 192, 0, 223, 204, 137, 211, 115, 33, 42, 68, 227, 65, 161, 17, 116, 138, 195, 51, 51, 181, 183, 124, 119, 161, 74, 202, 21, 182, 195, 134, 198, 191, 182, 223, 205, 60, 175, 207, 223, 232, 94, 133, 70, 10, 127, 100, 170, 109, 22]).slice(0, 16)
const derived = (async () => {
const keyMaterial = await crypto.subtle.importKey(
@ -21,7 +21,7 @@ const derived = (async () => {
},
keyMaterial,
{
name: 'AES-GCM',
name: 'AES-CBC',
length: 256
},
false,
@ -32,7 +32,7 @@ const derived = (async () => {
export async function encryptMessage (message: string) {
return hex2bin(arr2hex(new Uint8Array(await crypto.subtle.encrypt(
{
name: 'AES-GCM',
name: 'AES-CBC',
iv: key
},
await derived,
@ -43,7 +43,7 @@ export async function encryptMessage (message: string) {
export async function decryptMessage (encryptedMessage: string) {
return arr2text(await crypto.subtle.decrypt(
{
name: 'AES-GCM',
name: 'AES-CBC',
iv: key
},
await derived,

View file

@ -1,13 +1,18 @@
import Client, { createChannelConstructor } from '@thaunknown/web-irc'
import { writable } from 'simple-store-svelte'
import { toast } from 'svelte-sonner'
import { decryptMessage, encryptMessage } from './crypt'
import type { ChatMessage, ChatUser } from '$lib/components/ui/chat'
import type IrcChannel from '@thaunknown/web-irc/channel'
import type IrcClient from '@thaunknown/web-irc/client'
import type { EventEmitter } from 'events'
import { page } from '$app/state'
import { MessageToast, type ChatMessage, type ChatUser } from '$lib/components/ui/chat'
export const prevAgreed = writable(false)
export type UserType = 'al' | 'guest'
export interface IRCChatUser {
nick: string
@ -99,12 +104,20 @@ export default class MessageClient {
this.irc.on('privmsg', async priv => {
try {
const message = await decryptMessage(priv.message)
this.messages.update(messages => [...messages, {
const msg: ChatMessage = {
message,
user: this.users.value[priv.ident]!,
type: 'incoming',
date: new Date(priv.time)
}])
}
if (page.route.id !== '/app/chat' && !msg.user.name.startsWith('Guest-')) {
toast.custom(MessageToast, {
classes: { toast: '!bg-transparent w-full !shadow-none h-auto flex' },
componentProps: { msg }
})
}
this.messages.update(messages => [...messages, msg])
} catch (e) {
// some1 sent a message without encryption
console.error(e)
@ -154,4 +167,9 @@ export default class MessageClient {
})
return client
}
destroy () {
this.irc.removeAllListeners()
this.irc.connection?.end()
}
}

View file

@ -1,16 +1,13 @@
<script lang='ts' context='module'>
let prevAgreed = false
</script>
<script lang='ts'>
import TriangleAlert from 'lucide-svelte/icons/triangle-alert'
import { Button } from '$lib/components/ui/button'
import { IRC } from '$lib/components/ui/irc'
import { prevAgreed } from '$lib/modules/irc'
let agreed = prevAgreed
let agreed = $prevAgreed
function agree () {
agreed = prevAgreed = true
agreed = $prevAgreed = true
}
</script>