checkpoint progress on experiences/demo

This commit is contained in:
AtHeartEngineer
2023-09-06 18:08:03 -04:00
parent c33aaac1e9
commit 24491127ee
8 changed files with 167 additions and 38 deletions

View File

@@ -1,4 +1,11 @@
<script lang="ts">
import Group from 'svelte-material-icons/AccountGroup.svelte';
import MemberSecret from 'svelte-material-icons/AccountKey.svelte';
import FingerPrint from 'svelte-material-icons/Fingerprint.svelte';
</script>
<div class="flex flex-row gap-3 place-items-center text-xl">
<FingerPrint />(<MemberSecret />)
<div></div>
<Group />
</div>

View File

@@ -1,31 +1,45 @@
<script>
import Button from '$lib/components/button.svelte';
import Demo from '$lib/components/Demo.svelte';
</script>
<div class="mx-auto mt-10 max-w-[80ch]">
<img src="/logo-text.png" alt="discreetly" class="max-h-20 mb-5" />
<h5 class="italic mb-4 mt-1">A new take on anonymous communication.</h5>
<h5 class="italic mb-4 mt-1">A new take on group chats.</h5>
<p class="text-justify my-3">
This feels like a mostly familiar chat application, with random numbers as usernames, but I
assure you there is more going on here.
This feels like a mostly familiar chat application, except there aren't user names. Under the
hood, there is no "login", the server doesn't know who you are, you are anonymous. You're
completely anonymous. <i class="italic">Unless you break the rules.</i>
</p>
<p class="text-justify my-3">
Under the hood, there is no "login", the server doesn't know who you are, you are anonymous.
The beauty of this system is that it fosters trust among group members, knowing that everyone in
the chat is a verified member. At the same time, it provides the freedom to express oneself
anonymously.
</p>
<p class="text-justify my-3">
There is one catch, if you send messages too fast, someone can figure out which identity you
are, and remove you from the chat. So if you try to break the rules, you will be removed, and
there is no undo.
When you want to send a message in a room, you need to verify your membership in that room, but
without giving away your identity. This is accomplished using a zero-knowledge proof, a clever
piece of cryptography that lets you prove you know something, without having to reveal what that
something is.
</p>
<p>
When you send a message, your device generates a zk proof that you are a member of that room,
and that you haven't sent too many messages during some time period (an epoch), but doesn't
reveal which member you are.
<p class="text-justify my-3">
However, there's a small catch. To prevent spam, each time you send a message, you "share" a
tiny piece of your identity that is only useful for that epoch (time period). If you send too
many messages during an epoch, someone can reassemble your identity, all of your messages can be
linked together, and you will be removed from the chat for spamming. This is done automatically
and permanently, there is no unban.
</p>
<p class="text-justify my-3">
Read more about <a class="anchor" href="https://rate-limiting-nullifier.github.io/rln-docs/"
>RLN</a
>.
</p>
<a href="https://discord.gg/brJQ36KVxk" class="btn variant-ghost-secondary">Join our Discord</a>
<div>
<Demo />
</div>
</div>

View File

@@ -10,7 +10,8 @@
<style>
#chat-wrapper {
height: 100%;
height: 100vh;
max-height: calc(100vh - 56px);
display: grid;
grid-template-columns: minmax(17%, 300px) 1fr;
grid-template-rows: auto;

View File

@@ -1,21 +1,29 @@
<script lang="ts">
import ChatRoomHeader from './ChatRoomHeader.svelte';
import InputPrompt from './InputPrompt.svelte';
import Conversation from './Conversation.svelte';
import { onMount, onDestroy } from 'svelte';
import { selectedServer, currentSelectedRoom, messageStore, rateLimitStore } from '$lib/stores';
import { io } from 'socket.io-client';
import type { Socket } from 'socket.io-client';
import type { MessageI } from 'discreetly-interfaces';
import { getEpochFromTimestamp, getTimestampFromEpoch, updateMessages } from '$lib/utils';
import Loading from '$lib/components/loading.svelte';
import {
currentSelectedRoom,
messageStore,
rateLimitStore,
selectedServer,
configStore
} from '$lib/stores';
import { Experiences } from '$lib/types';
import { getEpochFromTimestamp, getTimestampFromEpoch, updateMessages } from '$lib/utils';
import { toastStore } from '@skeletonlabs/skeleton';
import type { MessageI } from 'discreetly-interfaces';
import type { Socket } from 'socket.io-client';
import { io } from 'socket.io-client';
import { onDestroy, onMount } from 'svelte';
import Conversation from './Conversation.svelte';
import Draw from './Draw.svelte';
import InputPrompt from './InputPrompt.svelte';
let scrollChatToBottom: () => {};
let socket: Socket;
let connected: boolean = false;
let lastRoom = '';
let onlineMembers = '?';
$: currentEpoch = 0;
$: timeLeftInEpoch = '0';
$: roomId = $currentSelectedRoom.roomId!.toString();
@@ -41,8 +49,8 @@
messagesSent: 0
};
console.debug('MessagesLeft() resetting epoch for room', roomId);
return userMessageLimit;
} else {
return userMessageLimit;
} else {
console.debug('MessagesLeft() returning messages left for room', roomId);
return userMessageLimit - $rateLimitStore[roomId].messagesSent;
}
@@ -71,13 +79,16 @@
}
onMount(() => {
console.log('MESSAGES LEFT: ' + messagesLeft());
socket = io($selectedServer);
socket.on('connect', () => {
connected = true;
const engine = socket.io.engine;
updateMessages($selectedServer, $currentSelectedRoom?.roomId.toString());
scrollChatToBottom();
if ($configStore.experience == Experiences.Chat) {
scrollChatToBottom();
}
engine.once('upgrade', () => {
console.debug('Upgraded connection to', engine.transport.name);
@@ -131,7 +142,8 @@
scrollChatToBottom();
}
socket.on('Members', (data: string) => {
console.debug(data);
console.debug(`Members Online: ${data}`);
onlineMembers = data;
});
socket.on('systemBroadcast', (data: string) => {
@@ -153,7 +165,6 @@
{#if $currentSelectedRoom}
<div id="chat" class="grid grid-rows-[auto,1fr,auto]">
<!-- Header -->
<ChatRoomHeader
{connected}
{currentEpoch}
@@ -163,19 +174,36 @@
{messagesLeft}
{roomRateLimit}
/>
{#if $configStore.experience == Experiences.Chat}
{#key $currentSelectedRoom.roomId}
<Conversation bind:scrollChatBottom={scrollChatToBottom} {roomRateLimit} />
{/key}
<InputPrompt
{socket}
{connected}
{currentEpoch}
{userMessageLimit}
{messageId}
{messagesLeft}
/>
{:else if $configStore.experience == Experiences.Draw}
<Draw />
{:else}
{#key $currentSelectedRoom.roomId}
<Conversation bind:scrollChatBottom={scrollChatToBottom} {roomRateLimit} />
{/key}
<InputPrompt
{socket}
{connected}
{currentEpoch}
{userMessageLimit}
{messageId}
{messagesLeft}
/>
{/if}
<!-- Conversation -->
{#key $currentSelectedRoom.roomId}
<Conversation bind:scrollChatBottom={scrollChatToBottom} {roomRateLimit} />
{/key}
<!-- Prompt -->
<InputPrompt
{socket}
{connected}
{currentEpoch}
{userMessageLimit}
{messageId}
{messagesLeft}
/>
</div>
{:else}
<Loading />

View File

@@ -1,9 +1,10 @@
<script lang="ts">
import AP from '$lib/components/AP.svelte';
import Clock from '$lib/components/Clock.svelte';
import { configStore, currentSelectedRoom } from '$lib/stores';
import { currentSelectedRoom } from '$lib/stores';
import { ProgressBar } from '@skeletonlabs/skeleton';
import FullCircle from 'svelte-material-icons/Circle.svelte';
import ExperienceMenu from './ExperienceMenu.svelte';
export let connected: boolean;
export let currentEpoch: number;
export let timeLeftInEpoch: string;
@@ -40,6 +41,7 @@
class="flex flex-row place-content-center"
title={`These are action points, you get ${userMessageLimit} every ${epochLengthSeconds} seconds`}
>
<ExperienceMenu />
<AP health={messagesLeft()} maxHealth={userMessageLimit} />
<div class="block sm:hidden">
<Clock time={timeToNextEpoch} maxTime={epochLengthSeconds} />

View File

@@ -0,0 +1,43 @@
<script lang="ts">
import { onMount } from 'svelte';
let canvas: HTMLCanvasElement;
let ctx: CanvasRenderingContext2D;
const aspectRatio = 1;
// Resize function
function resizeCanvas() {
const parent = canvas.parentElement;
console.log(parent);
const parentWidth = parent!.clientWidth;
const parentHeight = parent!.clientHeight;
console.log(parentWidth, parentHeight);
let height, width;
if (parentHeight < parentWidth / aspectRatio) {
height = parentHeight;
width = height * aspectRatio;
} else {
width = parentWidth;
height = width / aspectRatio;
}
canvas.width = width;
canvas.height = height;
}
onMount(() => {
canvas = document.getElementById('drawing-canvas') as HTMLCanvasElement;
ctx = canvas.getContext('2d')!;
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
});
</script>
<canvas
id="drawing-canvas"
width="250"
height="250"
class="border border-surface-300-600-token m-1 sm:m-3"
/>

View File

@@ -0,0 +1,27 @@
<script lang="ts">
import { Experiences } from '$lib/types';
import Palette from 'svelte-material-icons/Palette.svelte';
import Chat from 'svelte-material-icons/Chat.svelte';
import { configStore } from '$lib/stores';
$: experience = $configStore.experience;
function nextExperience() {
if (experience == Experiences.Chat) {
$configStore.experience = Experiences.Draw;
} else if (experience == Experiences.Draw) {
$configStore.experience = Experiences.Chat;
} else {
$configStore.experience = Experiences.Chat;
}
}
</script>
<span on:click={nextExperience} class="flex flex-row ms-2 place-items-center">
{#if experience == Experiences.Chat}
<Palette class="w-5 h-5" />
{:else if experience == Experiences.Draw}
<Chat class="w-5 h-5" />
{:else}
<Palette class="w-5 h-5" />
{/if}
</span>

View File

@@ -73,6 +73,13 @@
$rateLimitStore[$currentSelectedRoom.roomId!.toString()].messagesSent,
'messages sent this epoch'
);
} else {
$rateLimitStore[$currentSelectedRoom.roomId!.toString()].lastEpoch = currentEpoch;
$rateLimitStore[$currentSelectedRoom.roomId!.toString()].messagesSent = 1;
console.debug(
$rateLimitStore[$currentSelectedRoom.roomId!.toString()].messagesSent,
'messages sent this epoch'
);
}
socket.emit('validateMessage', msg);
console.debug('Sending message: ', msg);