This commit is contained in:
AtHeartEngineer
2023-07-06 12:00:51 -04:00
parent 6a8a2ffadc
commit bbd097b3ff
67 changed files with 25066 additions and 1976 deletions

View File

@@ -10,8 +10,31 @@ A room can be created by the server owner/admin, with certain criteria/barrier t
### Karma Culling
In an anonmyous chat, it is (basically) impossible to know who said something the large majority didn't agree with, but you can prove that you *didn't* say something. So we can use this to exclude very bad actors using a karma system where users can upvote or downvote messages, which under the hood are non-inclusion proofs, essentially saying "i didn't create this post, and I did or didn't like this".
In an anonmyous chat, it is (basically) impossible to know who said something the large majority didn't agree with, but you can prove that you _didn't_ say something. So we can use this to exclude very bad actors using a karma system where users can upvote or downvote messages, which under the hood are non-inclusion proofs, essentially saying "i didn't create this post, and I did or didn't like this".
> This non-inclusion proof includes a new "transiition identity commitment".
After a certain amount of time (configurable by the server, maybe 1 day to start and over time move to 30 days?), the group can choose to transition, where the server would generate a new version of the room, and everyone would have to make a new semaphore proof with either their old identity commitment or a new one, and everyone who wants to participate in the room would have to make a non-inclusion proof for any of the messages that broke some UPVOTE/DOWNVOTE threshold (configurable by the server, something like 2x more downvotes than upvotes, and [over 20 votes total] | [10% of the room] | [the lowest voted post]).
After a certain trigger (maybe a certain amount of time like 1 day to start and over time move to every 30 days? or after a certain action on chain), the group can choose to transition, where the server would generate a new version of the room, and everyone would have to make a new semaphore proof with either their old identity commitment or a new one, and everyone who wants to participate in the room would have to make a non-inclusion proof for any of the messages that broke some UPVOTE/DOWNVOTE threshold (configurable by the server, something like 2x more downvotes than upvotes, and [over 20 votes total] | [10% of the room] | [the lowest voted post]).
This would result in multiple iterations of a room, one for each transition, and the rate limit would change per iteration.
- Most Recent Room (T)
- 1s
- T-1
- 10s
- T-2
- 100s // 1:40
- T-3
- 1000s // 16:40
- T-4
- 10000s // 2:46:40
- T-5
- 100000s // 27:46:40 // 1 day 3 hours 46 minutes 40 seconds
- T-6
- 1000000s // 11:13:46:40 // 11 days 13 hours 46 minutes 40 seconds
- T-7
- 10000000s // 1:03:13:46:40 // 1 month 3 days 13 hours 46 minutes 40 seconds
- T-8
- 100000000s // 11:09:03:13:46:40 // 11 months 9 days 3 hours 13 minutes 46 seconds 40 milliseconds
- T-9
- 1000000000s // 3:01:09:03:13:46:40 // 3 years 1 month 9 days 3 hours 13 minutes 46 seconds 40 milliseconds

21378
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,133 @@
/*
This is experimenting with the idea of transitioning different versions of a room based on filtering "bad actors" using non-inclusion proofs.
Essentially, if certain messages are flagged by the community as "bad actors", then all users that want to transition to the next room must provide a non-inclusion proof that they did not produce the bad message.
This really is going to only be used for extreme circumstances.
*/
interface User {
u: number;
name: string;
bad?: boolean | number;
transition?: boolean;
}
let users = [
{ u: 1, bad: false, transition: false, name: 'Alice' },
{ u: 2, bad: false, transition: false, name: 'Bob' },
{ u: 3, bad: false, transition: false, name: 'Carol' },
{ u: 4, bad: false, transition: false, name: 'Dave' },
{ u: 5, bad: false, transition: false, name: 'Eve' },
{ u: 6, bad: false, transition: false, name: 'Frank' },
{ u: 7, bad: false, transition: false, name: 'Grace' },
{ u: 8, bad: false, transition: false, name: 'Heidi' },
{ u: 9, bad: false, transition: false, name: 'Ivan' },
{ u: 10, bad: false, transition: false, name: 'Judy' },
{ u: 11, bad: false, transition: false, name: 'Mallory' },
{ u: 12, bad: false, transition: false, name: 'Oscar' },
{ u: 13, bad: false, transition: false, name: 'Peggy' },
{ u: 14, bad: false, transition: false, name: 'Sybil' },
{ u: 15, bad: false, transition: false, name: 'Trent' },
{ u: 16, bad: false, transition: false, name: 'Walter' },
{ u: 17, bad: false, transition: false, name: 'Wendy' }
];
class members {
room0: User[];
room1: User[];
room2: User[];
room3: User[];
rooms: User[][];
epoch: number;
constructor(members: User[]) {
this.epoch = 0;
this.room0 = members;
this.room1 = [];
this.room2 = [];
this.room3 = [];
this.rooms = [this.room0, this.room1, this.room2, this.room3];
this.stats('Initial');
}
public runEpoch() {
this.epoch++;
this.evaluateEpoch();
this.stats('Starting');
this.transitionEpoch();
this.stats('Ending');
}
stats(Title: string = '') {
console.log(Title, 'Epoch: ', this.epoch);
this.rooms.forEach((room, index) => {
console.log(
'Room:',
index,
'Members:',
room.length,
'baddies:',
room.reduce((acc, user) => acc + (user.bad ? 1 : 0), 0),
'Want to Transition:',
room.reduce((acc, user) => acc + (user.transition ? 1 : 0), 0)
);
});
}
evaluateEpoch(badPercentage: number = 0.05, transitionPercentage: number = 0.6) {
this.rooms.forEach((room, index) => {
//console.log("Evaluating Room: ", index)
if (room.length > 0) {
// Make random users bad
for (let i = 0; i < badPercentage * room.length; i++) {
const index = Math.floor(Math.random() * room.length);
room[index].bad = this.epoch;
//console.log("Marking user as bad: ", room[index].name)
}
// Make random users transition
let transitioning = 0;
let maxrounds = room.length * 2;
while (transitioning < transitionPercentage * room.length && maxrounds-- > 0) {
const index = Math.floor(Math.random() * room.length);
if (!room[index].transition) {
console.log('Marking user as transitioning: ', index);
room[index].transition = true;
transitioning++;
}
}
}
});
}
transitionEpoch() {
this.rooms.forEach((room, index) => {
if (room.length > 0 && index < this.rooms.length - 1) {
// Make random users bad
room.forEach((user) => {
if (user.transition && !user.bad) {
user.bad = false;
user.transition = false;
this.rooms[index + 1].push(user);
room.splice(room.indexOf(user), 1);
} else {
user.transition = false;
user.bad = false;
}
});
}
});
}
}
let m = new members(users);
m.runEpoch();
m.runEpoch();
m.runEpoch();
m.runEpoch();
m.runEpoch();
m.runEpoch();
m.runEpoch();
m.runEpoch();
m.runEpoch();
m.runEpoch();
console.log(m.rooms);

View File

@@ -0,0 +1,13 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock

View File

@@ -0,0 +1,30 @@
module.exports = {
root: true,
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:svelte/recommended',
'prettier'
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020,
extraFileExtensions: ['.svelte']
},
env: {
browser: true,
es2017: true,
node: true
},
overrides: [
{
files: ['*.svelte'],
parser: 'svelte-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser'
}
}
]
};

10
packages/frontend-svelte/.gitignore vendored Normal file
View File

@@ -0,0 +1,10 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*

View File

@@ -0,0 +1,2 @@
engine-strict=true
resolution-mode=highest

View File

@@ -0,0 +1,13 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock

View File

@@ -0,0 +1,9 @@
{
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte"],
"pluginSearchDirs": ["."],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}

View File

@@ -0,0 +1,38 @@
# create-svelte
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).
## Creating a project
If you're seeing this, you've probably already done this step. Congrats!
```bash
# create a new project in the current directory
npm create svelte@latest
# create a new project in my-app
npm create svelte@latest my-app
```
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
## Building
To create a production version of your app:
```bash
npm run build
```
You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.

View File

@@ -0,0 +1,34 @@
{
"name": "discreetly",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"test": "playwright test",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --plugin-search-dir . --check . && eslint .",
"format": "prettier --plugin-search-dir . --write ."
},
"devDependencies": {
"@playwright/test": "^1.28.1",
"@sveltejs/adapter-auto": "^2.1.0",
"@sveltejs/kit": "^1.21.0",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"eslint": "^8.28.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-svelte": "^2.30.0",
"prettier": "^2.8.0",
"prettier-plugin-svelte": "^2.10.1",
"svelte": "^4.0.0",
"svelte-check": "^1.0.61",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"vite": "^4.3.6"
},
"dependencies": {},
"type": "module"
}

View File

@@ -0,0 +1,12 @@
import type { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
webServer: {
command: 'npm run build && npm run preview',
port: 4173
},
testDir: 'tests',
testMatch: /(.+\.)?(test|spec)\.[jt]s/
};
export default config;

12
packages/frontend-svelte/src/app.d.ts vendored Normal file
View File

@@ -0,0 +1,12 @@
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
declare global {
namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface Platform {}
}
}
export {};

View File

@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width" />
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
rel="stylesheet"
crossorigin="anonymous"
/>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
crossorigin="anonymous"
></script>
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>

View File

@@ -0,0 +1,15 @@
import type { RoomGroupI } from '$lib/types';
export const roomGroups: RoomGroupI[] = [
{
name: 'Loading...',
rooms: [
{
id: BigInt(0),
name: 'Loading Rooms',
membership: {
identityCommitments: [BigInt(0)]
}
}
]
}
];

View File

@@ -0,0 +1,23 @@
import type {
MembershipI,
RoomGroupI,
ServerI,
RoomI,
MessageI,
SystemMessageI,
IdentityCommitmentT,
RLNContractI,
Server
} from '../../../protocol-interfaces/src/main';
export type {
RoomI,
MessageI,
MembershipI,
RoomGroupI,
ServerI,
SystemMessageI,
IdentityCommitmentT,
RLNContractI,
Server
};

View File

@@ -0,0 +1,8 @@
import { poseidon2 } from 'poseidon-lite/poseidon2';
export function genId(serverID: bigint, roomName: string | bigint | number) {
if (typeof roomName === 'string') {
return poseidon2([serverID, BigInt(Buffer.from(roomName).toString('hex', 16))]);
}
return poseidon2([serverID, BigInt(roomName)]);
}

View File

@@ -0,0 +1,3 @@
<div>
<h3>Error!</h3>
</div>

View File

@@ -0,0 +1,86 @@
<script lang="ts">
import { onMount } from 'svelte';
import type { ServerI } from '$lib/types';
import AppHeader from './AppHeader.svelte';
import AppFooter from './AppFooter.svelte';
(BigInt.prototype as any).toJSON = function () {
return this.toString();
};
let servers: ServerI[] = [];
let selectedServer: ServerI;
function setSelectedServer(server: ServerI) {
console.debug('setting selected server');
selectedServer = server;
}
onMount(async () => {
console.info('fetching servers');
// TODO: Handle multiple servers
fetch('http://localhost:3001/api/', {
method: 'GET',
headers: {
'Access-Control-Allow-Origin': '*'
}
})
.then(async (response) => {
servers[0] = await response.json();
console.debug(servers);
// TODO: Handle case where no servers are available or server is already selected in localstorage
selectedServer = servers[0];
})
.catch((err) => {
console.error(err);
});
});
</script>
<div class="d-flex flex-column align-content-between">
<AppHeader {servers} {setSelectedServer} {selectedServer} />
<main class="container-fluid align-items-center align-self-stretch">
{#if selectedServer}
<slot server={selectedServer}>
{/if}
</slot>
</main>
<AppFooter />
</div>
<style>
:root {
--blackish: rgba(0, 0, 0, 0.98);
--gray-dark: #212121;
--gray-light: rgba(242, 242, 242, 0.6);
--white: rgba(255, 255, 255, 1);
--whitish: rgb(225, 225, 225);
--steel: hsl(185, 18%, 50%);
--steel-light: hsl(185, 18%, 66%);
--steel-dark: hsl(185, 18%, 33%);
--neon-green: #59f02b;
--green: #19d457;
--green-light: #61f291;
--green-dark: #198754;
--jade: #45a164;
--hunter-green: #405c37;
--dark-blue: #315db5;
--blue: #477eed;
--blue-light: #53d3e0;
--blue-very-light: #a7f6ff;
--violet: #9198e5;
--violet-light: #b4bbff;
--mauve: #cc71c2;
--pink: #bf2c7f;
--purple: #b638f5;
--sunset: #ff7575;
--sunset-light: #ffb585;
--orangered: #fa5f5f;
--max-red: #de1a1a;
--yellow: #fad14b;
}
main {
margin-top: calc(0.5rem + 51px);
}
</style>

View File

@@ -0,0 +1,4 @@
<script lang="ts">
</script>
<h2>HOMEPAGE</h2>

View File

@@ -0,0 +1,12 @@
<div class="container">
<footer class="py-3 my-4">
<ul class="nav justify-content-center border-bottom pb-3 mb-3">
<li class="nav-item"><a href="/" class="nav-link px-2 text-body-secondary">Home</a></li>
<li class="nav-item"><a href="/signup" class="nav-link px-2 text-body-secondary">Signup</a></li>
<li class="nav-item"><a href="/login" class="nav-link px-2 text-body-secondary">Login</a></li>
<li class="nav-item"><a href="/chat" class="nav-link px-2 text-body-secondary">Chat</a></li>
<li class="nav-item"><a href="/about" class="nav-link px-2 text-body-secondary">About</a></li>
</ul>
<p class="text-center text-body-secondary">© 2023 Privacy & Scaling Explorations</p>
</footer>
</div>

View File

@@ -0,0 +1,99 @@
<script lang="ts">
import type { ServerI } from '$lib/types';
export let servers: ServerI[] = [];
export let selectedServer: ServerI = { name: 'Loading' } as ServerI;
export let setSelectedServer: (server: ServerI) => void;
</script>
<header>
<nav class="navbar fixed-top navbar-dark bg-dark navbar-expand-lg">
<div class="container-fluid d-flex align-content-between">
<div class="d-flex">
<a class="navbar-brand d-none d-md-block" href="#">Discreetly</a>
<div class="collapse navbar-collapse" id="navbarText">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<a class="navbar-brand d-block d-md-none" href="#">Discreetly</a>
<li class="nav-item">
<a href="/" class="nav-link">Home</a>
</li>
<li class="nav-item">
<a href="/chat" class="nav-link">Chat</a>
</li>
<li class="nav-item d-block d-lg-none">
<a href="/signup" class="nav-link">Signup</a>
</li>
<li class="nav-item d-block d-lg-none">
<a href="/login" class="nav-link">Login</a>
</li>
</ul>
</div>
</div>
<div class="navbar-brand dropdown" id="server-title">
<a
class="nav-link dropdown-toggle"
href="#"
role="button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
{selectedServer.name}
</a>
<ul class="dropdown-menu">
{#each servers as server}
<li>
<div
aria-label={'select ' + server.name}
class="dropdown-item"
on:click={() => setSelectedServer(server)}
on:keydown={(event) => {
if (event.key === 'Enter' || event.key === ' ') {
setSelectedServer(server);
}
}}
role="button"
tabindex="0"
>
{server.name}
</div>
</li>
{/each}
</ul>
</div>
<div>
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item d-none d-lg-block">
<a href="/signup" class="nav-link">Signup</a>
</li>
<li class="nav-item d-none d-lg-block">
<a href="/login" class="nav-link">Login</a>
</li>
</ul>
<button
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarText"
aria-controls="navbarText"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon" />
</button>
</div>
</div>
</nav>
</header>
<style>
.navbar-dark .navbar-brand {
color: var(--orangered);
}
#server-title {
font-family: 'Space Mono';
color: var(--steel-light);
}
.nav-link {
color: var(--steel);
}
</style>

View File

@@ -0,0 +1,21 @@
<script lang="ts">
import RoomList from './RoomList.svelte';
import type { ServerI } from '$lib/types';
export let server: ServerI;
let room = server.roomGroups
.map((group) => group.rooms)
.flat()
.find((room) => room.id === server.selectedRoom);
function selectRoom(id: ServerI['selectedRoom']) {
server.selectedRoom = id;
console.log('selectRoom');
}
</script>
<div class="container-fluid">
<RoomList roomGroups={server.roomGroups} {selectRoom} />
<slot {server} />
</div>

View File

@@ -0,0 +1,7 @@
<script lang="ts">
import type { ServerI } from '$lib/types';
export let server: ServerI;
</script>
{server}

View File

@@ -0,0 +1,25 @@
<script lang="ts">
import type { RoomGroupI } from '$lib/types';
export let roomGroups: RoomGroupI[];
export let selectRoom: (id: string) => void = () => {};
</script>
<h2>Pick a chat room</h2>
<section id="roomList">
{#each roomGroups as group}
<h3>{group.name}</h3>
asdf
<ul class="list-group">
{#each group.rooms as room}
<div class="card" style="width: 18rem;">
<div class="card-body" on:click={selectRoom(room.id)}>
<h5 class="card-title">{room.name}</h5>
<p class="card-text">Members: {room.membership?.identityCommitments?.length}</p>
<a href="/chat/{room.name}" class="btn btn-primary">Join</a>
</div>
</div>
{/each}
</ul>
{/each}
</section>

View File

@@ -0,0 +1,37 @@
<script lang="ts">
import { page } from '$app/stores';
import { onMount } from 'svelte';
import { goto } from '$app/navigation';
import type { RoomI, ServerI } from '$lib/types';
export let server: ServerI;
let room: RoomI | undefined;
onMount(() => {
let roomNamePath = $page.params.room;
room = server.roomGroups
.map((group) => group.rooms)
.flat()
.find((room) => room.name === roomNamePath);
if (!room) {
console.log('no room, redirecting to /chat');
goto('/chat');
} else {
server.selectedRoom = room.id;
}
});
</script>
<div class="chat-room">
<h3>{room?.name}</h3>
<div class="chat-messages">
<div class="chat-message">
<p>
<strong>internalNullfiier</strong>: message
</p>
</div>
</div>
<div class="chat-input">
<input type="text" placeholder="Type your message here" />
</div>
</div>

View File

@@ -0,0 +1,33 @@
<script lang="ts">
import { page } from "$app/stores";
</script>
<nav class="flex justify-center my-6">
<ul class="steps">
<a href="/signup" class="step step-primary">Sign Up</a>
<a
href="/signup/gates"
class="step"
class:step-primary={$page.route.id?.match(/gates|ceremony|backup/g)}>
Choose Communities
</a>
<a
href="/signup/ceremony"
class="step"
class:step-primary={$page.route.id?.match(/ceremony|backup/g)}>
Create Identity
</a>
<a
href="/signup/backup"
class="step"
class:step-primary={$page.route.id?.match(/backup/g)}>
Backup Identity
</a>
</ul>
</nav>
<main class="card w-4/6 bg-neutral text-neutral-content mx-auto">
<div class="card-body items-center text-center">
<slot />
</div>
</main>

View File

@@ -0,0 +1,5 @@
<div class="min-h-screen flex flex-col">
<div>Signup</div>
<slot />
</div>

View File

@@ -0,0 +1 @@
<div>BACKUP IDENTITY</div>

View File

@@ -0,0 +1 @@
<div>IDENTITY CREATION CEREMONY</div>

View File

@@ -0,0 +1 @@
<div>GATES</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,21 @@
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/kit/vite';
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
preprocess: vitePreprocess(),
kit: {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter()
},
build: {
sourcemap: true // Config vite to generate sourcemap when bundling.
},
};
export default config;

View File

@@ -0,0 +1,6 @@
import { expect, test } from '@playwright/test';
test('index page has expected h1', async ({ page }) => {
await page.goto('/');
await expect(page.getByRole('heading', { name: 'Welcome to SvelteKit' })).toBeVisible();
});

View File

@@ -0,0 +1,17 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
//
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in
}

View File

@@ -0,0 +1,6 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [sveltekit()]
});

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -1,4 +1,4 @@
import { RLNFullProof } from 'rlnjs';
import type { RLNFullProof } from 'rlnjs';
export type IdentityCommitmentT = bigint;
@@ -10,7 +10,7 @@ export enum RoomType {
}
export interface MembershipI {
identityCommitment?: IdentityCommitmentT[];
identityCommitments?: IdentityCommitmentT[];
rlnContract?: RLNContractI;
}
@@ -38,7 +38,7 @@ export interface RoomI {
rateLimit?: number; // Messages per minute
membership?: MembershipI; // List of Identity Commitments, or a contract address for an RLN contract
type?: RoomType; // Public or private
messageHandlerSocket?: number; // Port for websocket connections
messageHandlerSocket?: string; // Port for websocket connections
}
export interface RoomGroupI {
@@ -53,4 +53,62 @@ export interface ServerI {
messageHandlerSocket?: string; // Default port for websocket connections
publicMembership?: MembershipI;
roomGroups: RoomGroupI[];
selectedRoom?: RoomI['id'];
}
export class Server {
name: string;
version: string | undefined;
serverInfoEndpoint: string;
messageHandlerSocket: string | undefined;
publicMembership: MembershipI | undefined;
roomGroups: RoomGroupI[];
selectedRoom: string | bigint;
constructor(public server: ServerI) {
this.name = server.name;
this.version = server.version;
this.serverInfoEndpoint = server.serverInfoEndpoint;
this.messageHandlerSocket = server.messageHandlerSocket;
this.publicMembership = server.publicMembership;
this.roomGroups = server.roomGroups;
this.selectedRoom = server.selectedRoom
? server.selectedRoom
: server.roomGroups[0].rooms[0].id;
}
getRoomById(id: string | bigint): RoomI | undefined {
return this.roomGroups
.map((group) => group.rooms)
.flat()
.find((room) => room.id === id);
}
getRoomByName(name: string): RoomI | undefined {
return this.roomGroups
.map((group) => group.rooms)
.flat()
.find((room) => room.name === name);
}
getRoomGroupByName(name: string): RoomGroupI | undefined {
return this.roomGroups.find((group) => group.name === name);
}
setRoomById(id: string | bigint) {
if (this.getRoomById(id)) {
this.selectedRoom = id;
return id;
} else {
return -1;
}
}
getRoomHandlerSocket(id: string | bigint): string | undefined {
const room = this.getRoomById(id);
if (room) {
return room.messageHandlerSocket;
} else {
return this.messageHandlerSocket;
}
}
}

View File

@@ -30,6 +30,17 @@ export const rooms: RoomGroupI[] = [
id: genId(serverID, '1EthRoom'),
name: '1EthRoom',
membership: [idcommitment_1, idcommitment_2, idcommitment_5] as MembershipI
},
{
id: genId(serverID, 'Test'),
name: 'Test',
membership: [
idcommitment_1,
idcommitment_2,
idcommitment_3,
idcommitment_4,
idcommitment_5
] as MembershipI
}
]
},

View File

@@ -59,12 +59,12 @@ app.use(
})
);
app.get('/', (req, res) => {
app.get(['/', '/api'], (req, res) => {
console.log('fetching server info');
res.json(serverConfig);
});
app.get('/rooms', (req, res) => {
app.get('/api/rooms', (req, res) => {
console.log('fetching rooms');
res.json(rooms);
});

View File

@@ -1,5 +1,8 @@
import { poseidon2 } from 'poseidon-lite/poseidon2';
export function genId(serverID: bigint, roomName: string | bigint | number) {
if (typeof roomName === 'string') {
return poseidon2([serverID, BigInt(Buffer.from(roomName).toString('hex', 16))]);
}
return poseidon2([serverID, BigInt(roomName)]);
}

4796
yarn.lock

File diff suppressed because it is too large Load Diff