mirror of
https://github.com/Rate-Limiting-Nullifier/Discreetly.git
synced 2026-01-08 20:18:04 -05:00
svelte
This commit is contained in:
@@ -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
21378
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
133
packages/experiments/nonInclusionProofs.ts
Normal file
133
packages/experiments/nonInclusionProofs.ts
Normal 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);
|
||||
13
packages/frontend-svelte/.eslintignore
Normal file
13
packages/frontend-svelte/.eslintignore
Normal 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
|
||||
30
packages/frontend-svelte/.eslintrc.cjs
Normal file
30
packages/frontend-svelte/.eslintrc.cjs
Normal 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
10
packages/frontend-svelte/.gitignore
vendored
Normal 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-*
|
||||
2
packages/frontend-svelte/.npmrc
Normal file
2
packages/frontend-svelte/.npmrc
Normal file
@@ -0,0 +1,2 @@
|
||||
engine-strict=true
|
||||
resolution-mode=highest
|
||||
13
packages/frontend-svelte/.prettierignore
Normal file
13
packages/frontend-svelte/.prettierignore
Normal 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
|
||||
9
packages/frontend-svelte/.prettierrc
Normal file
9
packages/frontend-svelte/.prettierrc
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"useTabs": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 100,
|
||||
"plugins": ["prettier-plugin-svelte"],
|
||||
"pluginSearchDirs": ["."],
|
||||
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
|
||||
}
|
||||
38
packages/frontend-svelte/README.md
Normal file
38
packages/frontend-svelte/README.md
Normal 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.
|
||||
34
packages/frontend-svelte/package.json
Normal file
34
packages/frontend-svelte/package.json
Normal 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"
|
||||
}
|
||||
12
packages/frontend-svelte/playwright.config.ts
Normal file
12
packages/frontend-svelte/playwright.config.ts
Normal 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
12
packages/frontend-svelte/src/app.d.ts
vendored
Normal 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 {};
|
||||
22
packages/frontend-svelte/src/app.html
Normal file
22
packages/frontend-svelte/src/app.html
Normal 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>
|
||||
15
packages/frontend-svelte/src/lib/rooms.ts
Normal file
15
packages/frontend-svelte/src/lib/rooms.ts
Normal 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)]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
23
packages/frontend-svelte/src/lib/types.ts
Normal file
23
packages/frontend-svelte/src/lib/types.ts
Normal 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
|
||||
};
|
||||
8
packages/frontend-svelte/src/lib/utils.ts
Normal file
8
packages/frontend-svelte/src/lib/utils.ts
Normal 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)]);
|
||||
}
|
||||
3
packages/frontend-svelte/src/routes/+error.svelte
Normal file
3
packages/frontend-svelte/src/routes/+error.svelte
Normal file
@@ -0,0 +1,3 @@
|
||||
<div>
|
||||
<h3>Error!</h3>
|
||||
</div>
|
||||
86
packages/frontend-svelte/src/routes/+layout.svelte
Normal file
86
packages/frontend-svelte/src/routes/+layout.svelte
Normal 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>
|
||||
4
packages/frontend-svelte/src/routes/+page.svelte
Normal file
4
packages/frontend-svelte/src/routes/+page.svelte
Normal file
@@ -0,0 +1,4 @@
|
||||
<script lang="ts">
|
||||
</script>
|
||||
|
||||
<h2>HOMEPAGE</h2>
|
||||
12
packages/frontend-svelte/src/routes/AppFooter.svelte
Normal file
12
packages/frontend-svelte/src/routes/AppFooter.svelte
Normal 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>
|
||||
99
packages/frontend-svelte/src/routes/AppHeader.svelte
Normal file
99
packages/frontend-svelte/src/routes/AppHeader.svelte
Normal 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>
|
||||
21
packages/frontend-svelte/src/routes/chat/+layout.svelte
Normal file
21
packages/frontend-svelte/src/routes/chat/+layout.svelte
Normal 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>
|
||||
7
packages/frontend-svelte/src/routes/chat/+page.svelte
Normal file
7
packages/frontend-svelte/src/routes/chat/+page.svelte
Normal file
@@ -0,0 +1,7 @@
|
||||
<script lang="ts">
|
||||
import type { ServerI } from '$lib/types';
|
||||
|
||||
export let server: ServerI;
|
||||
</script>
|
||||
|
||||
{server}
|
||||
25
packages/frontend-svelte/src/routes/chat/RoomList.svelte
Normal file
25
packages/frontend-svelte/src/routes/chat/RoomList.svelte
Normal 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>
|
||||
37
packages/frontend-svelte/src/routes/chat/[room]/+page.svelte
Normal file
37
packages/frontend-svelte/src/routes/chat/[room]/+page.svelte
Normal 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>
|
||||
33
packages/frontend-svelte/src/routes/signup/+layout.svelte
Normal file
33
packages/frontend-svelte/src/routes/signup/+layout.svelte
Normal 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>
|
||||
5
packages/frontend-svelte/src/routes/signup/+page.svelte
Normal file
5
packages/frontend-svelte/src/routes/signup/+page.svelte
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
<div class="min-h-screen flex flex-col">
|
||||
<div>Signup</div>
|
||||
<slot />
|
||||
</div>
|
||||
@@ -0,0 +1 @@
|
||||
<div>BACKUP IDENTITY</div>
|
||||
@@ -0,0 +1 @@
|
||||
<div>IDENTITY CREATION CEREMONY</div>
|
||||
@@ -0,0 +1 @@
|
||||
<div>GATES</div>
|
||||
BIN
packages/frontend-svelte/static/favicon.png
Normal file
BIN
packages/frontend-svelte/static/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
21
packages/frontend-svelte/svelte.config.js
Normal file
21
packages/frontend-svelte/svelte.config.js
Normal 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;
|
||||
6
packages/frontend-svelte/tests/test.ts
Normal file
6
packages/frontend-svelte/tests/test.ts
Normal 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();
|
||||
});
|
||||
17
packages/frontend-svelte/tsconfig.json
Normal file
17
packages/frontend-svelte/tsconfig.json
Normal 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
|
||||
}
|
||||
6
packages/frontend-svelte/vite.config.ts
Normal file
6
packages/frontend-svelte/vite.config.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()]
|
||||
});
|
||||
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
0
packages/frontend-vue/server/api/servers.ts
Normal file
0
packages/frontend-vue/server/api/servers.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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)]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user