mirror of
https://github.com/Discreetly/frontend.git
synced 2026-01-08 04:23:56 -05:00
init
This commit is contained in:
13
.eslintignore
Normal file
13
.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
.eslintrc.cjs
Normal file
30
.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
.gitignore
vendored
Normal file
10
.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-*
|
||||
13
.prettierignore
Normal file
13
.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
.prettierrc
Normal file
9
.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
README.md
Normal file
38
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.
|
||||
3979
package-lock.json
generated
Normal file
3979
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
41
package.json
Normal file
41
package.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"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 .",
|
||||
"prepare": "svelte-kit sync"
|
||||
},
|
||||
"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.5",
|
||||
"svelte-check": "^3.4.5",
|
||||
"svelte-kit": "^1.2.0",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^4.3.6"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@semaphore-protocol/group": "^3.10.1",
|
||||
"discreetly-interfaces": "^0.1.0",
|
||||
"poseidon-lite": "^0.2.0",
|
||||
"socket.io-client": "^4.7.1"
|
||||
}
|
||||
}
|
||||
12
playwright.config.ts
Normal file
12
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;
|
||||
174
src/app.css
Normal file
174
src/app.css
Normal file
@@ -0,0 +1,174 @@
|
||||
: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(184, 18%, 50%);
|
||||
--steel-rgb: 105, 147, 150;
|
||||
--steel-white: hsl(185, 28%, 95%);
|
||||
--steel-very-light: hsl(185, 28%, 88%);
|
||||
--steel-light: hsl(185, 18%, 66%);
|
||||
--steel-bright: hsl(185, 75%, 33%);
|
||||
--steel-bright-rg: 21, 137, 147;
|
||||
--steel-dark: hsl(185, 18%, 33%);
|
||||
--steel-night: hsl(185, 12%, 12%);
|
||||
--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;
|
||||
--bs-body-color: var(--steel-night);
|
||||
--bs-body-color-rgb: 225, 225, 225;
|
||||
--bs-body-bg: var(--steel-very-light);
|
||||
--bs-body-bg-rgb: 213, 225, 226;
|
||||
--bs-emphasis-color: #fff;
|
||||
--bs-emphasis-color-rgb: 255, 255, 255;
|
||||
--bs-secondary-color: var(--steel);
|
||||
--bs-secondary-color-rgb: var(--steel-rgb);
|
||||
--bs-secondary-bg: var(--whitish);
|
||||
--bs-secondary-bg-rgb: 52, 58, 64;
|
||||
--bs-tertiary-color: rgba(173, 181, 189, 0.5);
|
||||
--bs-tertiary-color-rgb: 173, 181, 189;
|
||||
--bs-tertiary-bg: #2b3035;
|
||||
--bs-tertiary-bg-rgb: 43, 48, 53;
|
||||
--bs-primary-text-emphasis: #6ea8fe;
|
||||
--bs-secondary-text-emphasis: #a7acb1;
|
||||
--bs-success-text-emphasis: #75b798;
|
||||
--bs-info-text-emphasis: #6edff6;
|
||||
--bs-warning-text-emphasis: #ffda6a;
|
||||
--bs-danger-text-emphasis: #ea868f;
|
||||
--bs-light-text-emphasis: #f8f9fa;
|
||||
--bs-dark-text-emphasis: #dee2e6;
|
||||
--bs-primary-bg-subtle: #031633;
|
||||
--bs-secondary-bg-subtle: #161719;
|
||||
--bs-success-bg-subtle: #051b11;
|
||||
--bs-info-bg-subtle: #032830;
|
||||
--bs-warning-bg-subtle: #332701;
|
||||
--bs-danger-bg-subtle: #2c0b0e;
|
||||
--bs-light-bg-subtle: #343a40;
|
||||
--bs-dark-bg-subtle: #1a1d20;
|
||||
--bs-primary-border-subtle: var(--steel-light);
|
||||
--bs-secondary-border-subtle: #41464b;
|
||||
--bs-success-border-subtle: #0f5132;
|
||||
--bs-info-border-subtle: #087990;
|
||||
--bs-warning-border-subtle: #997404;
|
||||
--bs-danger-border-subtle: #842029;
|
||||
--bs-light-border-subtle: #495057;
|
||||
--bs-dark-border-subtle: #343a40;
|
||||
--bs-heading-color: var(--orangered);
|
||||
--bs-link-color: #6ea8fe;
|
||||
--bs-link-hover-color: #8bb9fe;
|
||||
--bs-link-color-rgb: 110, 168, 254;
|
||||
--bs-link-hover-color-rgb: 139, 185, 254;
|
||||
--bs-code-color: #e685b5;
|
||||
--bs-border-color: var(--steel-dark);
|
||||
--bs-border-color-translucent: var(--steel-dark);
|
||||
--bs-form-valid-color: #75b798;
|
||||
--bs-form-valid-border-color: #75b798;
|
||||
--bs-form-invalid-color: #ea868f;
|
||||
--bs-form-invalid-border-color: #ea868f;
|
||||
--bs-font-sans-serif: 'Space Grotesk', Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", sans-serif;
|
||||
--bs-font-monospace: 'Space Mono', monospace;
|
||||
--bs-link-hover-color: var(--steel-bright);
|
||||
--bs-link-hover-color-rgb: var(--steel-bright-rgb);
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
background-image: radial-gradient(ellipse, var(--steel-dark), var(--steel-night));
|
||||
color: transparent;
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
--bs-btn-color: var(--steel-white);
|
||||
--bs-btn-bg: var(--steel-bright);
|
||||
--bs-btn-border-color: var(--steel-dark);
|
||||
--bs-btn-hover-color: var(--steel-white);
|
||||
--bs-btn-hover-bg: var(--orangered);
|
||||
--bs-btn-hover-border-color: var(--max-red);
|
||||
--bs-btn-focus-shadow-rgb: 49, 132, 253;
|
||||
--bs-btn-active-color: var(--steel-white);
|
||||
--bs-btn-active-bg: var(--sunset);
|
||||
--bs-btn-active-border-color: var(--orangered);
|
||||
--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
|
||||
--bs-btn-disabled-color: var(--steel-dark);
|
||||
--bs-btn-disabled-bg: var(--steel-night);
|
||||
--bs-btn-disabled-border-color: var(--orangered);
|
||||
}
|
||||
|
||||
.nav {
|
||||
--bs-nav-link-padding-x: 1rem;
|
||||
--bs-nav-link-padding-y: 0.5rem;
|
||||
--bs-nav-link-color: var(--steel-dark);
|
||||
--bs-nav-link-hover-color: var(--steel-bright);
|
||||
--bs-nav-link-disabled-color: var(--bs-secondary-color);
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
color: var(--steel);
|
||||
}
|
||||
|
||||
.nav-underline .nav-link.active,
|
||||
.nav-underline .show>.nav-link {
|
||||
color: var(--steel-bright);
|
||||
}
|
||||
|
||||
.nav-link:focus,
|
||||
.nav-link:hover {
|
||||
color: var(--steel-bright);
|
||||
}
|
||||
|
||||
a.nav-link:hover,
|
||||
a.btn:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--steel-bright);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--steel);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
border: 1px solid var(--steel-dark);
|
||||
border-radius: 0.5em;
|
||||
padding: 0.35rem 0.5rem;
|
||||
background-color: var(--steel-white);
|
||||
}
|
||||
|
||||
input:focus-visible,
|
||||
textarea:focus-visible {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 0.15em var(--steel-bright);
|
||||
}
|
||||
12
src/app.d.ts
vendored
Normal file
12
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 {};
|
||||
28
src/app.html
Normal file
28
src/app.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<!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>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<!-- TODO host fonts ourselves to stop the google tracking machine -->
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
4
src/hooks.ts
Normal file
4
src/hooks.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
// FIXME: This is a potential hack to get proofs to generate on the front end
|
||||
export async function handle({ event, resolve }) {
|
||||
return resolve(event, { ssr: false });
|
||||
}
|
||||
14
src/lib/button.svelte
Normal file
14
src/lib/button.svelte
Normal file
@@ -0,0 +1,14 @@
|
||||
<script lang="ts">
|
||||
import type { ButtonI } from './types';
|
||||
export let button: ButtonI;
|
||||
</script>
|
||||
|
||||
<a
|
||||
href={button.link}
|
||||
class="btn btn-lg px-4 d-inline-flex align-items-center {button.class
|
||||
? button.class
|
||||
: 'btn-primary'}"
|
||||
type="button"
|
||||
>
|
||||
{button.text}
|
||||
</a>
|
||||
18
src/lib/card.svelte
Normal file
18
src/lib/card.svelte
Normal file
@@ -0,0 +1,18 @@
|
||||
<script lang="ts">
|
||||
import type { ButtonI } from './types';
|
||||
import Button from './button.svelte';
|
||||
export let title: string;
|
||||
export let buttons: ButtonI[] = [];
|
||||
</script>
|
||||
|
||||
<div class="m-4 px-5 py-4 text-center bg-body-tertiary rounded-2">
|
||||
<h2 class="text-body-emphasis m-3">{title}</h2>
|
||||
<div class="col-lg-8 mx-auto fs-5 text-muted">
|
||||
<slot />
|
||||
</div>
|
||||
<div class="d-inline-flex gap-5 my-3">
|
||||
{#each buttons as button}
|
||||
<Button {button} />
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
15
src/lib/rooms.ts
Normal file
15
src/lib/rooms.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import type { RoomGroupI } from 'discreetly-interfaces';
|
||||
export const roomGroups: RoomGroupI[] = [
|
||||
{
|
||||
name: 'Loading...',
|
||||
rooms: [
|
||||
{
|
||||
id: BigInt(0),
|
||||
name: 'Loading Rooms',
|
||||
membership: {
|
||||
identityCommitments: [BigInt(0)]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
61
src/lib/stores.ts
Normal file
61
src/lib/stores.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { writable } from 'svelte/store';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
// This is just a list of endpoints of servers to connect to, no other information, this is mainly for bootstraping the app
|
||||
export const serverListStore = storable(['http://localhost:3001/api/'], 'servers');
|
||||
|
||||
// This is what gets populated after querying the serverListStore, with the server's information, public rooms available, etc.
|
||||
export const serverDataStore = storable({}, 'serverData');
|
||||
|
||||
// JUST an index to the serverDataStore, so we can keep track of which server we're currently connected to
|
||||
export const selectedServer = storable({}, 'selectedServer');
|
||||
|
||||
// Session store (removed after the session is cleared) of the last 500 messages or so of each room the user participates in; rooms they don't have selected will not be updated
|
||||
export const messageStore = sessionable({}, 'messages');
|
||||
|
||||
// Stores the user's identity // TODO THIS NEEDS TO BE AN ENCRYPTED SEMAPHORE IDENTITY IN THE FUTURE
|
||||
export const identityStore = storable({}, 'identity');
|
||||
|
||||
export function storable(data: any, storagePath = 'storable') {
|
||||
const store = writable(data);
|
||||
const { subscribe, set, update } = store;
|
||||
const isBrowser = typeof window !== 'undefined';
|
||||
|
||||
isBrowser && localStorage[storagePath] && set(JSON.parse(localStorage[storagePath]));
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
set: (n: object | string | number) => {
|
||||
browser && (localStorage[storagePath] = JSON.stringify(n));
|
||||
set(n);
|
||||
},
|
||||
update: (cb) => {
|
||||
const updatedStore = cb(get(store));
|
||||
|
||||
browser && (localStorage[storagePath] = JSON.stringify(updatedStore));
|
||||
set(updatedStore);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function sessionable(data: any, storagePath = 'storable') {
|
||||
const store = writable(data);
|
||||
const { subscribe, set, update } = store;
|
||||
const isBrowser = typeof window !== 'undefined';
|
||||
|
||||
isBrowser && sessionStorage[storagePath] && set(JSON.parse(sessionStorage[storagePath]));
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
set: (n: object | string | number) => {
|
||||
browser && (sessionStorage[storagePath] = JSON.stringify(n));
|
||||
set(n);
|
||||
},
|
||||
update: (cb) => {
|
||||
const updatedStore = cb(get(store));
|
||||
|
||||
browser && (sessionStorage[storagePath] = JSON.stringify(updatedStore));
|
||||
set(updatedStore);
|
||||
}
|
||||
};
|
||||
}
|
||||
7
src/lib/types.ts
Normal file
7
src/lib/types.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
interface ButtonI {
|
||||
link: string;
|
||||
text: string;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
export type { ButtonI };
|
||||
68
src/lib/utils.ts
Normal file
68
src/lib/utils.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import type { Identity } from '@semaphore-protocol/identity';
|
||||
import type { MessageI, RoomI, ServerI } from 'discreetly-interfaces';
|
||||
import { randomBigInt, genId, str2BigInt } from 'discreetly-interfaces';
|
||||
import { RLNProver, type RLNFullProof, type MerkleProof } from 'rlnjs';
|
||||
import { poseidon1 } from 'poseidon-lite/poseidon1';
|
||||
import { Group } from '@semaphore-protocol/group';
|
||||
import { poseidon2 } from 'poseidon-lite/poseidon2';
|
||||
|
||||
const wasmPath = '/rln/circuit.wasm';
|
||||
const zkeyPath = '/rln/final.zkey';
|
||||
const prover: RLNProver = new RLNProver(wasmPath, zkeyPath);
|
||||
|
||||
interface proofInputsI {
|
||||
rlnIdentifier: bigint;
|
||||
identitySecret: bigint;
|
||||
userMessageLimit: bigint;
|
||||
messageId: bigint;
|
||||
merkleProof: MerkleProof;
|
||||
x: bigint;
|
||||
epoch: bigint;
|
||||
}
|
||||
|
||||
async function genProof(room: RoomI, message: string, identity: Identity): Promise<MessageI> {
|
||||
const userMessageLimit = BigInt(1);
|
||||
const messageHash: bigint = poseidon1([str2BigInt(message)]);
|
||||
const group = new Group(room.id, 20, room.membership?.identityCommitments);
|
||||
const rateCommitment: bigint = poseidon2([identity.getCommitment(), userMessageLimit]);
|
||||
group.addMember(rateCommitment); // FIXME: This is just a hack to add the user to the group for testing
|
||||
const proofInputs: proofInputsI = {
|
||||
rlnIdentifier: BigInt(room.id),
|
||||
identitySecret: identity.getSecret(),
|
||||
userMessageLimit: userMessageLimit,
|
||||
messageId: BigInt(0),
|
||||
merkleProof: group.generateMerkleProof(group.indexOf(rateCommitment)),
|
||||
x: messageHash,
|
||||
epoch: BigInt(Date.now().toString())
|
||||
};
|
||||
//console.debug('PROOFINPUTS:', proofInputs);
|
||||
return prover.generateProof(proofInputs).then((proof: RLNFullProof) => {
|
||||
console.log('Proof generated!');
|
||||
const msg: MessageI = {
|
||||
id: proof.snarkProof.publicSignals.nullifier.toString(),
|
||||
message: message,
|
||||
room: BigInt(proof.snarkProof.publicSignals.externalNullifier),
|
||||
proof
|
||||
};
|
||||
return msg;
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchServer(server_url: string): Promise<ServerI | void> {
|
||||
console.debug(`Fetching server ${server_url}`);
|
||||
return fetch(server_url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': 'http://localhost:*'
|
||||
}
|
||||
})
|
||||
.then(async (response): Promise<ServerI> => {
|
||||
const serverData: ServerI = await response.json();
|
||||
return serverData;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
|
||||
export { genProof, randomBigInt, genId, fetchServer };
|
||||
8
src/routes/+error.svelte
Normal file
8
src/routes/+error.svelte
Normal file
@@ -0,0 +1,8 @@
|
||||
<script>
|
||||
import { error } from '@sveltejs/kit';
|
||||
</script>
|
||||
|
||||
<div class="container-fluid w-75 my-3">
|
||||
<h3>Error!</h3>
|
||||
<p>{error}</p>
|
||||
</div>
|
||||
55
src/routes/+layout.svelte
Normal file
55
src/routes/+layout.svelte
Normal file
@@ -0,0 +1,55 @@
|
||||
<script lang="ts">
|
||||
import '../app.css';
|
||||
import { onMount } from 'svelte';
|
||||
import AppHeader from './AppHeader.svelte';
|
||||
import AppFooter from './AppFooter.svelte';
|
||||
import { identityStore, serverListStore, serverDataStore, selectedServer } from '$lib/stores';
|
||||
import { Identity } from '@semaphore-protocol/identity';
|
||||
import type { ServerI } from 'discreetly-interfaces';
|
||||
import { fetchServer } from '$lib/utils';
|
||||
|
||||
(BigInt.prototype as any).toJSON = function () {
|
||||
return this.toString();
|
||||
};
|
||||
|
||||
function setSelectedServer(server: number) {
|
||||
console.debug('setting selected server');
|
||||
selectedServer.set(server);
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
$serverListStore.forEach((server: string) => {
|
||||
console.log('fetching server data');
|
||||
fetchServer(server).then((data) => {
|
||||
console.log('setting server data');
|
||||
console.log(data);
|
||||
console.log(server);
|
||||
$serverDataStore[server] = data as ServerI;
|
||||
console.log($serverDataStore);
|
||||
});
|
||||
});
|
||||
if ($selectedServer.name == undefined) {
|
||||
$selectedServer = $serverListStore[0];
|
||||
}
|
||||
});
|
||||
|
||||
// TODO THIS IS ONLY FOR DEVELOPMENT AND SHOULD BE REMOVED AFTER SIGNUP IS SETUP
|
||||
if (!$identityStore['_nullifier']) {
|
||||
console.log('MAKING UP SECRETS');
|
||||
$identityStore = new Identity();
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="d-flex flex-column align-content-between">
|
||||
<AppHeader {setSelectedServer} />
|
||||
<main class="container-fluid align-items-center align-self-stretch">
|
||||
<slot />
|
||||
</main>
|
||||
<AppFooter />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
main {
|
||||
margin-top: calc(52px);
|
||||
}
|
||||
</style>
|
||||
4
src/routes/+page.svelte
Normal file
4
src/routes/+page.svelte
Normal file
@@ -0,0 +1,4 @@
|
||||
<script lang="ts">
|
||||
</script>
|
||||
|
||||
<h2>HOMEPAGE</h2>
|
||||
14
src/routes/AppFooter.svelte
Normal file
14
src/routes/AppFooter.svelte
Normal file
@@ -0,0 +1,14 @@
|
||||
<div class="container-fluid">
|
||||
<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>
|
||||
113
src/routes/AppHeader.svelte
Normal file
113
src/routes/AppHeader.svelte
Normal file
@@ -0,0 +1,113 @@
|
||||
<script lang="ts">
|
||||
import { serverDataStore, selectedServer, serverListStore } from '$lib/stores';
|
||||
export let setSelectedServer: (server: number) => 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>
|
||||
{#if $serverDataStore[$selectedServer] != undefined}
|
||||
<div class="navbar-brand dropdown" id="server-title">
|
||||
<a
|
||||
class="nav-link dropdown-toggle"
|
||||
href="#"
|
||||
role="button"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
title={String($serverDataStore[$selectedServer].name + ' (' + $selectedServer + ')')}
|
||||
>
|
||||
{$serverDataStore[$selectedServer].name}
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
{#each $serverListStore as key}
|
||||
<li>
|
||||
<div
|
||||
aria-label={'select ' + $serverDataStore[key].name}
|
||||
class="dropdown-item"
|
||||
on:click={() => setSelectedServer(key)}
|
||||
on:keydown={(event) => {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
setSelectedServer(key);
|
||||
}
|
||||
}}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
title={String($serverDataStore[key].name + ' (' + key + ')')}
|
||||
>
|
||||
{$serverDataStore[key].name}
|
||||
</div>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
{/if}
|
||||
<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);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nav-link:hover {
|
||||
color: var(--steel-bright);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.dropdown-item:focus,
|
||||
.dropdown-item:hover {
|
||||
color: var(--blackish);
|
||||
background-color: var(--steel-bright);
|
||||
}
|
||||
</style>
|
||||
1
src/routes/about/+page.svelte
Normal file
1
src/routes/about/+page.svelte
Normal file
@@ -0,0 +1 @@
|
||||
Read more about <a href="https://rate-limiting-nullifier.github.io/rln-docs/">RLN</a>.
|
||||
61
src/routes/chat/+layout.svelte
Normal file
61
src/routes/chat/+layout.svelte
Normal file
@@ -0,0 +1,61 @@
|
||||
<script lang="ts">
|
||||
import RoomList from './RoomList.svelte';
|
||||
import ChatRoom from './ChatRoom.svelte';
|
||||
import type { RoomGroupI, RoomI } from 'discreetly-interfaces';
|
||||
import { serverDataStore, selectedServer } from '$lib/stores';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let room: RoomI;
|
||||
let loaded: Boolean = false;
|
||||
|
||||
function selectRoom(id: RoomI['id']) {
|
||||
$serverDataStore[$selectedServer].selectedRoom = id;
|
||||
setRoom(id as string);
|
||||
}
|
||||
|
||||
function setRoom(id: string) {
|
||||
const rooms = $serverDataStore[$selectedServer].roomGroups;
|
||||
const temp_room = rooms
|
||||
.map((group: RoomGroupI) => group.rooms)
|
||||
.flat()
|
||||
.find((room: RoomI) => room.id === id);
|
||||
|
||||
if (temp_room) {
|
||||
console.debug('Setting Room to Selected', temp_room.name);
|
||||
room = temp_room;
|
||||
} else if ($serverDataStore[$selectedServer].roomGroups[0]) {
|
||||
console.debug('Setting Room to Default');
|
||||
room = $serverDataStore[$selectedServer].roomGroups[0].rooms[0];
|
||||
} else {
|
||||
console.debug('Loading Rooms Still');
|
||||
room = {
|
||||
id: '0',
|
||||
name: 'Rooms Not Loaded',
|
||||
membership: { identityCommitments: [0n] }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
setRoom($serverDataStore[$selectedServer].selectedRoom as string);
|
||||
loaded = true;
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="container-fluid mt-2">
|
||||
<div class="row">
|
||||
{#if $serverDataStore[$selectedServer] && loaded}
|
||||
<RoomList {selectRoom} />
|
||||
{:else}
|
||||
<div class="col-12">
|
||||
<div class="alert alert-info" role="alert">Loading Room List...</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if room && loaded}
|
||||
<ChatRoom {room} />
|
||||
{:else}
|
||||
<slot />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
4
src/routes/chat/+page.svelte
Normal file
4
src/routes/chat/+page.svelte
Normal file
@@ -0,0 +1,4 @@
|
||||
<script lang="ts">
|
||||
</script>
|
||||
|
||||
<div class="col">Loading Server Rooms...</div>
|
||||
166
src/routes/chat/ChatRoom.svelte
Normal file
166
src/routes/chat/ChatRoom.svelte
Normal file
@@ -0,0 +1,166 @@
|
||||
<script lang="ts">
|
||||
import { identityStore, selectedServer, messageStore, serverDataStore } from '$lib/stores';
|
||||
import type { RoomI, MessageI } from 'discreetly-interfaces';
|
||||
import { io } from 'socket.io-client';
|
||||
import { onDestroy } from 'svelte';
|
||||
import { genProof } from '$lib/utils';
|
||||
import { Identity } from '@semaphore-protocol/identity';
|
||||
|
||||
export let room: RoomI;
|
||||
|
||||
if (!$messageStore[room.id.toString()]) {
|
||||
$messageStore[room.id.toString()] = [];
|
||||
}
|
||||
let messages = [...$messageStore[room.id.toString()]];
|
||||
|
||||
onDestroy(() => {
|
||||
socket.emit('leavingRoom', room?.id);
|
||||
socket.disconnect();
|
||||
});
|
||||
|
||||
let inputText = '';
|
||||
let sendButtonText = 'Send';
|
||||
|
||||
const socketURL: string = $serverDataStore[$selectedServer].messageHandlerSocket || '';
|
||||
|
||||
const socket = io(socketURL);
|
||||
let connected: boolean = false;
|
||||
|
||||
socket.on('connect', () => {
|
||||
connected = true;
|
||||
const engine = socket.io.engine;
|
||||
|
||||
engine.once('upgrade', () => {
|
||||
console.debug('Upgraded connection to', engine.transport.name);
|
||||
});
|
||||
|
||||
engine.on('close', (reason) => {
|
||||
console.debug('socket-io-transport-closed', reason);
|
||||
});
|
||||
|
||||
socket.emit('joiningRoom', room?.id);
|
||||
});
|
||||
|
||||
socket.on('disconnected', () => {
|
||||
connected = false;
|
||||
console.debug('disconnected');
|
||||
});
|
||||
|
||||
socket.on('connect_error', (err) => {
|
||||
console.debug('chat connection error', err.message);
|
||||
});
|
||||
|
||||
socket.on('connect_timeout', (err) => {
|
||||
console.debug('chat connection timeout', err.message);
|
||||
});
|
||||
|
||||
socket.on('error', (err) => {
|
||||
console.debug('chat websocket error', err.message);
|
||||
});
|
||||
|
||||
socket.on('messageBroadcast', (data: MessageI) => {
|
||||
messages = [data, ...messages];
|
||||
messages = messages.slice(0, 500);
|
||||
$messageStore[room.id.toString()] = messages;
|
||||
});
|
||||
|
||||
function sendMessage(message: string) {
|
||||
const identity = new Identity($identityStore.toString());
|
||||
genProof(room, message, identity).then((msg) => {
|
||||
socket.emit('validateMessage', msg);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="col chat-room">
|
||||
<h3 class="d-flex justify-content-between align-content-center">
|
||||
{room?.name}
|
||||
<span class="fs-6 fw-light align-self-center" style="color:gray">
|
||||
{#if connected}
|
||||
<div aria-label="Connected">🟢</div>
|
||||
{:else}
|
||||
<div aria-label="Disconnected">🔴</div>
|
||||
{/if}
|
||||
</span>
|
||||
</h3>
|
||||
<div id="messages" class="mb-3">
|
||||
<section>
|
||||
{#each messages as message}
|
||||
<div class="msg">
|
||||
<div class="msg-id">{message.id}</div>
|
||||
<span class="msg-text">{message.message}</span>
|
||||
</div>
|
||||
{/each}
|
||||
</section>
|
||||
</div>
|
||||
<div id="chat-input">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Type your message here"
|
||||
bind:value={inputText}
|
||||
on:keydown={(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
sendMessage(inputText);
|
||||
inputText = '';
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
class="btn btn-primary"
|
||||
on:click={() => {
|
||||
sendMessage(inputText);
|
||||
inputText = '';
|
||||
}}
|
||||
>
|
||||
{sendButtonText}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
#messages {
|
||||
border: 1px solid var(--steel-dark);
|
||||
border-radius: 0.5em;
|
||||
padding: 0.35rem 0.5rem;
|
||||
background-color: var(--steel-white);
|
||||
}
|
||||
|
||||
#messages section {
|
||||
overflow-y: scroll;
|
||||
max-height: 60vh;
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.msg {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.msg-id {
|
||||
font-family: 'Space Mono', monospace;
|
||||
color: var(--steel-dark);
|
||||
width: 12ch;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.msg-text::before {
|
||||
content: ':';
|
||||
color: var(--steel);
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
#chat-input {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
#chat-input input {
|
||||
flex-grow: 1;
|
||||
}
|
||||
</style>
|
||||
48
src/routes/chat/RoomList.svelte
Normal file
48
src/routes/chat/RoomList.svelte
Normal file
@@ -0,0 +1,48 @@
|
||||
<script lang="ts">
|
||||
import type { RoomGroupI, RoomI } from 'discreetly-interfaces';
|
||||
import { selectedServer, serverDataStore } from '$lib/stores';
|
||||
|
||||
$: roomGroups = $serverDataStore[$selectedServer].roomGroups;
|
||||
|
||||
export let selectRoom: (roomId: RoomI['id']) => any;
|
||||
|
||||
function getMembers(room: RoomI): string {
|
||||
let total: number | string = '0';
|
||||
total = room.membership?.identityCommitments?.length || '?';
|
||||
return total.toString();
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="col-3">
|
||||
<section id="roomList">
|
||||
{#each roomGroups as group}
|
||||
<h4 class="mb-2 pb-2 border-bottom">{group.name}</h4>
|
||||
<ul class="list-group my-2">
|
||||
{#each group.rooms as room, index}
|
||||
<div class="mb-2">
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<h5 class="flex-grow-1">{room.name}</h5>
|
||||
<div class="px-3">{getMembers(room)} Members</div>
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
on:click={selectRoom(room.id)}
|
||||
class="btn btn-sm btn-primary d-flex align-items-center"
|
||||
>
|
||||
💬
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</ul>
|
||||
{/each}
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.btn-sm {
|
||||
text-align: center !important;
|
||||
}
|
||||
</style>
|
||||
53
src/routes/signup/+layout.svelte
Normal file
53
src/routes/signup/+layout.svelte
Normal file
@@ -0,0 +1,53 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { identityStore } from '$lib/stores';
|
||||
|
||||
// TODO Check if Identity is created
|
||||
// TODO Check if Gates exist
|
||||
</script>
|
||||
|
||||
<ul class="nav nav-underline d-flex justify-content-evenly mt-3 mb-4">
|
||||
<li class="nav-item">
|
||||
<a
|
||||
class="nav-link"
|
||||
class:active={!$page.route.id?.match(/gates|ceremony|backup/g)}
|
||||
class:complete={$page.route.id?.match(/gates|ceremony|backup/g)}
|
||||
aria-current="page"
|
||||
href="/signup">Sign Up</a
|
||||
>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a
|
||||
class="nav-link"
|
||||
href="/signup/gates"
|
||||
class:active={$page.route.id?.match(/gates/g)}
|
||||
class:complete={$page.route.id?.match(/ceremony|backup/g)}>Choose Communities</a
|
||||
>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a
|
||||
class="nav-link"
|
||||
href="/signup/ceremony"
|
||||
class:complete={$page.route.id?.match(/backup/g)}
|
||||
class:active={$page.route.id?.match(/ceremony/g)}>Create Identity</a
|
||||
>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/signup/backup" class:active={$page.route.id?.match(/backup/g)}
|
||||
>Backup Identity</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="d-flex flex-column align-items-center">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.complete::after {
|
||||
content: '✓';
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
19
src/routes/signup/+page.svelte
Normal file
19
src/routes/signup/+page.svelte
Normal file
@@ -0,0 +1,19 @@
|
||||
<script lang="ts">
|
||||
import Card from '$lib/card.svelte';
|
||||
let links = [
|
||||
{
|
||||
link: '/about',
|
||||
text: 'Read More',
|
||||
class: 'btn-secondary'
|
||||
},
|
||||
{
|
||||
link: '/signup/gates',
|
||||
text: 'Continue ➡',
|
||||
class: 'btn-primary'
|
||||
}
|
||||
];
|
||||
</script>
|
||||
|
||||
<Card title="Welcome to Discreetly" buttons={links}>
|
||||
This app is a little different from what you're used to.
|
||||
</Card>
|
||||
12
src/routes/signup/backup/+page.svelte
Normal file
12
src/routes/signup/backup/+page.svelte
Normal file
@@ -0,0 +1,12 @@
|
||||
<script lang="ts">
|
||||
import Card from '$lib/card.svelte';
|
||||
let links = [
|
||||
{
|
||||
link: '/chat',
|
||||
text: 'Start Chatting ➡',
|
||||
class: 'btn-primary'
|
||||
}
|
||||
];
|
||||
</script>
|
||||
|
||||
<Card title="Backup Your Identity" buttons={links}>TODO</Card>
|
||||
17
src/routes/signup/ceremony/+page.svelte
Normal file
17
src/routes/signup/ceremony/+page.svelte
Normal file
@@ -0,0 +1,17 @@
|
||||
<script lang="ts">
|
||||
import Card from '$lib/card.svelte';
|
||||
let links = [
|
||||
{
|
||||
link: '/chat',
|
||||
text: 'Skip Backup',
|
||||
class: 'btn-secondary'
|
||||
},
|
||||
{
|
||||
link: '/signup/backup',
|
||||
text: 'Backup Identity ➡',
|
||||
class: 'btn-primary'
|
||||
}
|
||||
];
|
||||
</script>
|
||||
|
||||
<Card title="Generate Your Identity" buttons={links}>TODO</Card>
|
||||
36
src/routes/signup/gates/+page.svelte
Normal file
36
src/routes/signup/gates/+page.svelte
Normal file
@@ -0,0 +1,36 @@
|
||||
<script lang="ts">
|
||||
import Card from '$lib/card.svelte';
|
||||
|
||||
let links = [
|
||||
{
|
||||
link: '/signup/ceremony',
|
||||
text: 'Continue ➡',
|
||||
class: 'btn-primary'
|
||||
}
|
||||
];
|
||||
let code = '';
|
||||
|
||||
function addCode(code: string) {
|
||||
console.log(code);
|
||||
}
|
||||
</script>
|
||||
|
||||
<Card title="Join Communities">
|
||||
Invite Code: <input
|
||||
type="text"
|
||||
placeholder="Invite Code"
|
||||
bind:value={code}
|
||||
on:keydown={(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
addCode(code);
|
||||
code = '';
|
||||
} else if (event.key === ' ' || event.key === '-') {
|
||||
event.preventDefault();
|
||||
if (code.length > 0 && code[code.length - 1] !== '-') {
|
||||
code += '-';
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
BIN
static/favicon.png
Normal file
BIN
static/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
17
static/rln/circuit.config.toml
Normal file
17
static/rln/circuit.config.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[Circuit_Version]
|
||||
RLN_Version = 2
|
||||
RLN_Type = "rln"
|
||||
|
||||
[Circuit_Build]
|
||||
Circom_Version = "circom compiler 2.1.5"
|
||||
GitHub_URL = "https://github.com/Rate-Limiting-Nullifier/rln-circuits-v2.git"
|
||||
Git_Commit = "17f0fed"
|
||||
Compilation_Time = 1688818882
|
||||
|
||||
[Files]
|
||||
Wasm = "circuit.wasm"
|
||||
Wasm_SHA256SUM = "fa9586db68a9566fd9b3af6e8d7c66f5567b35647aa63a426f220375e9fa8c04"
|
||||
Zkey = "final.zkey"
|
||||
Zkey_SHA256SUM = "5eaad7aae4dcc269e7de5b4e1aad7578cc3316ce1e2923c72c0eacf8d8a7c3c1"
|
||||
Verification_Key = "verification_key.json"
|
||||
Verification_Key_SHA256SUM = "6a45165b480239cac8e2de450f488e37198a18297db55a9509589c14b7db59f7"
|
||||
BIN
static/rln/circuit.wasm
Normal file
BIN
static/rln/circuit.wasm
Normal file
Binary file not shown.
BIN
static/rln/final.zkey
Normal file
BIN
static/rln/final.zkey
Normal file
Binary file not shown.
114
static/rln/verification_key.json
Normal file
114
static/rln/verification_key.json
Normal file
@@ -0,0 +1,114 @@
|
||||
{
|
||||
"protocol": "groth16",
|
||||
"curve": "bn128",
|
||||
"nPublic": 5,
|
||||
"vk_alpha_1": [
|
||||
"20491192805390485299153009773594534940189261866228447918068658471970481763042",
|
||||
"9383485363053290200918347156157836566562967994039712273449902621266178545958",
|
||||
"1"
|
||||
],
|
||||
"vk_beta_2": [
|
||||
[
|
||||
"6375614351688725206403948262868962793625744043794305715222011528459656738731",
|
||||
"4252822878758300859123897981450591353533073413197771768651442665752259397132"
|
||||
],
|
||||
[
|
||||
"10505242626370262277552901082094356697409835680220590971873171140371331206856",
|
||||
"21847035105528745403288232691147584728191162732299865338377159692350059136679"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0"
|
||||
]
|
||||
],
|
||||
"vk_gamma_2": [
|
||||
[
|
||||
"10857046999023057135944570762232829481370756359578518086990519993285655852781",
|
||||
"11559732032986387107991004021392285783925812861821192530917403151452391805634"
|
||||
],
|
||||
[
|
||||
"8495653923123431417604973247489272438418190587263600148770280649306958101930",
|
||||
"4082367875863433681332203403145435568316851327593401208105741076214120093531"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0"
|
||||
]
|
||||
],
|
||||
"vk_delta_2": [
|
||||
[
|
||||
"3817638527075299341910923013750491829772293424386698324526317429044327254930",
|
||||
"16817041674734304676071688134655235316477394149172545683919861305510126014325"
|
||||
],
|
||||
[
|
||||
"15321616806892601534034512759307826486280009165298528953245727688557811743473",
|
||||
"6325777744419158965546141708181579937852352378408429766464847802592525079966"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0"
|
||||
]
|
||||
],
|
||||
"vk_alphabeta_12": [
|
||||
[
|
||||
[
|
||||
"2029413683389138792403550203267699914886160938906632433982220835551125967885",
|
||||
"21072700047562757817161031222997517981543347628379360635925549008442030252106"
|
||||
],
|
||||
[
|
||||
"5940354580057074848093997050200682056184807770593307860589430076672439820312",
|
||||
"12156638873931618554171829126792193045421052652279363021382169897324752428276"
|
||||
],
|
||||
[
|
||||
"7898200236362823042373859371574133993780991612861777490112507062703164551277",
|
||||
"7074218545237549455313236346927434013100842096812539264420499035217050630853"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"7077479683546002997211712695946002074877511277312570035766170199895071832130",
|
||||
"10093483419865920389913245021038182291233451549023025229112148274109565435465"
|
||||
],
|
||||
[
|
||||
"4595479056700221319381530156280926371456704509942304414423590385166031118820",
|
||||
"19831328484489333784475432780421641293929726139240675179672856274388269393268"
|
||||
],
|
||||
[
|
||||
"11934129596455521040620786944827826205713621633706285934057045369193958244500",
|
||||
"8037395052364110730298837004334506829870972346962140206007064471173334027475"
|
||||
]
|
||||
]
|
||||
],
|
||||
"IC": [
|
||||
[
|
||||
"4920513730204767532050733107749276406754520419375654722016092399980613788208",
|
||||
"10950491564509418434657706642388934308456795265036074733953533582377584967294",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"6815064660695497986531118446154820702646540722664044216580897159556261271171",
|
||||
"17838140936832571103329556013529166877877534025488014783346458943575275015438",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"16364982450206976302246609763791333525052810246590359380676749324389440643932",
|
||||
"17092624338100676284548565502349491320314889021833923882585524649862570629227",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"3679639231485547795420532910726924727560917141402837495597760107842698404034",
|
||||
"16213191511474848247596810551723578773353083440353745908057321946068926848382",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"9215428431027260354679105025212521481930206886203677270216204485256690813172",
|
||||
"934602510541226149881779979217731465262250233587980565969044391353665291792",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"8935861545794299876685457331391349387048184820319250771243971382360441890897",
|
||||
"4993459033694759724715904486381952906869986989682015547152342336961693234616",
|
||||
"1"
|
||||
]
|
||||
]
|
||||
}
|
||||
17
static/withdraw/circuit.config.toml
Normal file
17
static/withdraw/circuit.config.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[Circuit_Version]
|
||||
RLN_Version = 2
|
||||
RLN_Type = "withdraw"
|
||||
|
||||
[Circuit_Build]
|
||||
Circom_Version = "circom compiler 2.1.5"
|
||||
GitHub_URL = "https://github.com/Rate-Limiting-Nullifier/rln-circuits-v2.git"
|
||||
Git_Commit = "17f0fed"
|
||||
Compilation_Time = 1688818887
|
||||
|
||||
[Files]
|
||||
Wasm = "circuit.wasm"
|
||||
Wasm_SHA256SUM = "239bd578deea5eebf3cde5a9aeba22ba799d23d0aff6b9a8b153afd8d2cc191e"
|
||||
Zkey = "final.zkey"
|
||||
Zkey_SHA256SUM = "397b769ddcf0bd918e5a85566e978150917da38020ab8e9ce878a6492bf2bca8"
|
||||
Verification_Key = "verification_key.json"
|
||||
Verification_Key_SHA256SUM = "a00c881245625369f18593dcd796188f457bd9cb38c6772e662febf2faec6160"
|
||||
BIN
static/withdraw/circuit.wasm
Normal file
BIN
static/withdraw/circuit.wasm
Normal file
Binary file not shown.
BIN
static/withdraw/final.zkey
Normal file
BIN
static/withdraw/final.zkey
Normal file
Binary file not shown.
99
static/withdraw/verification_key.json
Normal file
99
static/withdraw/verification_key.json
Normal file
@@ -0,0 +1,99 @@
|
||||
{
|
||||
"protocol": "groth16",
|
||||
"curve": "bn128",
|
||||
"nPublic": 2,
|
||||
"vk_alpha_1": [
|
||||
"20491192805390485299153009773594534940189261866228447918068658471970481763042",
|
||||
"9383485363053290200918347156157836566562967994039712273449902621266178545958",
|
||||
"1"
|
||||
],
|
||||
"vk_beta_2": [
|
||||
[
|
||||
"6375614351688725206403948262868962793625744043794305715222011528459656738731",
|
||||
"4252822878758300859123897981450591353533073413197771768651442665752259397132"
|
||||
],
|
||||
[
|
||||
"10505242626370262277552901082094356697409835680220590971873171140371331206856",
|
||||
"21847035105528745403288232691147584728191162732299865338377159692350059136679"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0"
|
||||
]
|
||||
],
|
||||
"vk_gamma_2": [
|
||||
[
|
||||
"10857046999023057135944570762232829481370756359578518086990519993285655852781",
|
||||
"11559732032986387107991004021392285783925812861821192530917403151452391805634"
|
||||
],
|
||||
[
|
||||
"8495653923123431417604973247489272438418190587263600148770280649306958101930",
|
||||
"4082367875863433681332203403145435568316851327593401208105741076214120093531"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0"
|
||||
]
|
||||
],
|
||||
"vk_delta_2": [
|
||||
[
|
||||
"11983007890138271431646631339128325393343025477496193427884097571341594637227",
|
||||
"7369399572723042520302573420729576910581887995143697476970345965043452827346"
|
||||
],
|
||||
[
|
||||
"18498623948725074905368922260006856461276039836160071250761949723295691187028",
|
||||
"20253812994897318378765322974844822348210001364477588185294466023467389614920"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0"
|
||||
]
|
||||
],
|
||||
"vk_alphabeta_12": [
|
||||
[
|
||||
[
|
||||
"2029413683389138792403550203267699914886160938906632433982220835551125967885",
|
||||
"21072700047562757817161031222997517981543347628379360635925549008442030252106"
|
||||
],
|
||||
[
|
||||
"5940354580057074848093997050200682056184807770593307860589430076672439820312",
|
||||
"12156638873931618554171829126792193045421052652279363021382169897324752428276"
|
||||
],
|
||||
[
|
||||
"7898200236362823042373859371574133993780991612861777490112507062703164551277",
|
||||
"7074218545237549455313236346927434013100842096812539264420499035217050630853"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"7077479683546002997211712695946002074877511277312570035766170199895071832130",
|
||||
"10093483419865920389913245021038182291233451549023025229112148274109565435465"
|
||||
],
|
||||
[
|
||||
"4595479056700221319381530156280926371456704509942304414423590385166031118820",
|
||||
"19831328484489333784475432780421641293929726139240675179672856274388269393268"
|
||||
],
|
||||
[
|
||||
"11934129596455521040620786944827826205713621633706285934057045369193958244500",
|
||||
"8037395052364110730298837004334506829870972346962140206007064471173334027475"
|
||||
]
|
||||
]
|
||||
],
|
||||
"IC": [
|
||||
[
|
||||
"19490069286251317200471893224761952280235157078692599655063040494106083015102",
|
||||
"15613730057977833735664106983317680013118142165231654768046521650638333652991",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"1563543155852853229359605494188815884199915022658219002707722789976065966419",
|
||||
"858819375930654753672617171465307097688802650498051619587167586479724200799",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"3808889614445935800597561392085733302718838702771107544944545050886958022904",
|
||||
"13293649293049947010793838294353767499934999769633605908974566715226392122400",
|
||||
"1"
|
||||
]
|
||||
]
|
||||
}
|
||||
21
svelte.config.js
Normal file
21
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
tests/test.ts
Normal file
6
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
tsconfig.json
Normal file
17
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
vite.config.ts
Normal file
6
vite.config.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()]
|
||||
});
|
||||
Reference in New Issue
Block a user