mirror of
https://github.com/Discreetly/frontend.git
synced 2026-01-08 20:38:04 -05:00
checkpoint with overscroll issue
This commit is contained in:
5812
package-lock.json
generated
5812
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
38
package.json
38
package.json
@@ -1,17 +1,21 @@
|
|||||||
{
|
{
|
||||||
"name": "discreetly",
|
"name": "discreetly",
|
||||||
"version": "0.0.1",
|
"version": "0.3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"license": "GPL-3.0-or-later",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite dev",
|
"dev": "vite dev",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"test": "playwright test",
|
"test": "npm run test:unit && npm run test:e2e",
|
||||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch --output human --threshold error",
|
||||||
"lint": "prettier --plugin-search-dir . --check . && eslint .",
|
"lint": "prettier --plugin-search-dir . --check . && eslint .",
|
||||||
"format": "prettier --plugin-search-dir . --write .",
|
"format": "prettier --plugin-search-dir . --write .",
|
||||||
"prepare": "svelte-kit sync"
|
"test:e2e": "playwright test",
|
||||||
|
"test:unit": "vitest",
|
||||||
|
"test:unit:ui": "vitest --ui --open --watch",
|
||||||
|
"test:unit:coverage": "vitest run --coverage"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@faker-js/faker": "^8.0.2",
|
"@faker-js/faker": "^8.0.2",
|
||||||
@@ -22,36 +26,45 @@
|
|||||||
"@sveltejs/adapter-cloudflare": "^2.3.0",
|
"@sveltejs/adapter-cloudflare": "^2.3.0",
|
||||||
"@sveltejs/adapter-static": "^2.0.3",
|
"@sveltejs/adapter-static": "^2.0.3",
|
||||||
"@sveltejs/kit": "^1.25.0",
|
"@sveltejs/kit": "^1.25.0",
|
||||||
|
"@sveltejs/vite-plugin-svelte": "^2.4.6",
|
||||||
"@tailwindcss/forms": "^0.5.6",
|
"@tailwindcss/forms": "^0.5.6",
|
||||||
|
"@tailwindcss/typography": "0.5.10",
|
||||||
|
"@testing-library/svelte": "^4.0.3",
|
||||||
"@types/dompurify": "^3.0.2",
|
"@types/dompurify": "^3.0.2",
|
||||||
"@types/node": "^20.6.3",
|
"@types/node": "^20.6.3",
|
||||||
"@types/qrcode": "^1.5.1",
|
"@types/qrcode": "^1.5.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
||||||
"@typescript-eslint/parser": "^5.45.0",
|
"@typescript-eslint/parser": "^5.45.0",
|
||||||
|
"@vitest/ui": "^0.34.6",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
"eslint": "^8.28.0",
|
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-svelte": "^2.30.0",
|
"eslint-plugin-svelte": "^2.30.0",
|
||||||
|
"eslint": "^8.28.0",
|
||||||
|
"jsdom": "^22.1.0",
|
||||||
"lightningcss": "^1.21.7",
|
"lightningcss": "^1.21.7",
|
||||||
"postcss": "^8.4.24",
|
|
||||||
"postcss-load-config": "^4.0.1",
|
"postcss-load-config": "^4.0.1",
|
||||||
"prettier": "^2.8.0",
|
"postcss": "^8.4.24",
|
||||||
"prettier-plugin-svelte": "^2.10.1",
|
"prettier-plugin-svelte": "^2.10.1",
|
||||||
"rollup-plugin-sizes": "^1.0.5",
|
"prettier": "^2.8.0",
|
||||||
"svelte": "^4.0.5",
|
|
||||||
"svelte-check": "^3.4.5",
|
"svelte-check": "^3.4.5",
|
||||||
"svelte-kit": "^1.2.0",
|
"svelte-kit": "^1.2.0",
|
||||||
|
"svelte": "^4.0.5",
|
||||||
"tailwindcss": "^3.3.2",
|
"tailwindcss": "^3.3.2",
|
||||||
"terser": "^5.19.2",
|
"terser": "^5.19.2",
|
||||||
"tslib": "^2.4.1",
|
"tslib": "^2.4.1",
|
||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
"vite": "^4.3.6"
|
"vite-plugin-tailwind-purgecss": "0.1.3",
|
||||||
|
"vite": "^4.4.11",
|
||||||
|
"vitest": "0.32.2"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ethersproject/bytes": "^5.7.0",
|
"@ethersproject/bytes": "^5.7.0",
|
||||||
"@ethersproject/keccak256": "^5.7.0",
|
"@ethersproject/keccak256": "^5.7.0",
|
||||||
"@ethersproject/strings": "^5.7.0",
|
"@ethersproject/strings": "^5.7.0",
|
||||||
|
"@floating-ui/dom": "1.5.3",
|
||||||
|
"@personaelabs/spartan-ecdsa": "^2.3.0",
|
||||||
|
"@rainbow-me/rainbowkit": "^1.1.1",
|
||||||
"@semaphore-protocol/group": "^3.10.1",
|
"@semaphore-protocol/group": "^3.10.1",
|
||||||
"@semaphore-protocol/identity": "^3.10.1",
|
"@semaphore-protocol/identity": "^3.10.1",
|
||||||
"autolinker": "^4.0.0",
|
"autolinker": "^4.0.0",
|
||||||
@@ -65,6 +78,7 @@
|
|||||||
"qr-scanner": "^1.4.2",
|
"qr-scanner": "^1.4.2",
|
||||||
"qrcode": "^1.5.3",
|
"qrcode": "^1.5.3",
|
||||||
"socket.io-client": "^4.7.1",
|
"socket.io-client": "^4.7.1",
|
||||||
"svelte-material-icons": "^3.0.5"
|
"svelte-material-icons": "^3.0.5",
|
||||||
|
"wagmi": "^1.4.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
14
playwright.config.ts
Normal file
14
playwright.config.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import type { PlaywrightTestConfig } from '@playwright/test';
|
||||||
|
|
||||||
|
const config: PlaywrightTestConfig = {
|
||||||
|
webServer: {
|
||||||
|
command: 'npm run build && npm run preview',
|
||||||
|
port: 4173,
|
||||||
|
stdout: 'ignore',
|
||||||
|
stderr: 'ignore'
|
||||||
|
},
|
||||||
|
testDir: 'tests',
|
||||||
|
testMatch: /(.+\.)?(test|spec)\.[jt]s/
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
@@ -1,13 +1,6 @@
|
|||||||
const tailwindcss = require('tailwindcss');
|
module.exports = {
|
||||||
const autoprefixer = require('autoprefixer');
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
const config = {
|
autoprefixer: {}
|
||||||
plugins: [
|
}
|
||||||
//Some plugins, like tailwindcss/nesting, need to run before Tailwind,
|
|
||||||
tailwindcss(),
|
|
||||||
//But others, like autoprefixer, need to run after,
|
|
||||||
autoprefixer
|
|
||||||
]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = config;
|
|
||||||
|
|||||||
5
src/+error.svelte
Normal file
5
src/+error.svelte
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { page } from '$app/stores';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h1 class="h3">{$page.error.message}</h1>
|
||||||
@@ -8,6 +8,6 @@
|
|||||||
%sveltekit.head%
|
%sveltekit.head%
|
||||||
</head>
|
</head>
|
||||||
<body data-sveltekit-preload-data="hover" data-theme="discreetly-theme">
|
<body data-sveltekit-preload-data="hover" data-theme="discreetly-theme">
|
||||||
<div>%sveltekit.body%</div>
|
<div style="display: contents" class="h-full overflow-hidden">%sveltekit.body%</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -91,3 +91,7 @@ input:focus-visible {
|
|||||||
font-family: 'Nippo';
|
font-family: 'Nippo';
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rail-icon {
|
||||||
|
@apply w-full h3;
|
||||||
|
}
|
||||||
|
|||||||
12
src/error.html
Normal file
12
src/error.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>%sveltekit.error.message%</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Something didn't work right</h1>
|
||||||
|
<p>Status: %sveltekit.status%</p>
|
||||||
|
<p>Message: %sveltekit.error.message%</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
// FIXME: This is a potential hack to get proofs to generate on the front end
|
// FIXME: This is a potential hack to get proofs to generate on the front end
|
||||||
export async function handle({ event, resolve }) {
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
export async function handle({ event, resolve }: { event: unknown; resolve: any }) {
|
||||||
return resolve(event, { ssr: false });
|
return resolve(event, { ssr: false });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { Ratings } from '@skeletonlabs/skeleton';
|
||||||
import FullCircle from 'svelte-material-icons/Circle.svelte';
|
import FullCircle from 'svelte-material-icons/Circle.svelte';
|
||||||
import CircleEmpty from 'svelte-material-icons/CircleOutline.svelte';
|
import CircleEmpty from 'svelte-material-icons/CircleOutline.svelte';
|
||||||
|
|
||||||
@@ -9,11 +10,11 @@
|
|||||||
$: emptycircles = maxHealth - health;
|
$: emptycircles = maxHealth - health;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex flex-row ms-2 place-items-center">
|
<Ratings value={health} max={maxHealth} spacing="space-x-0">
|
||||||
{#each { length: fullcircles } as _, i}
|
<svelte:fragment slot="empty">
|
||||||
<FullCircle class="w-4 h-4 text-green-500" />
|
|
||||||
{/each}
|
|
||||||
{#each { length: emptycircles } as _, i}
|
|
||||||
<CircleEmpty class="w-4 h-4 text-surface-600-300-token" />
|
<CircleEmpty class="w-4 h-4 text-surface-600-300-token" />
|
||||||
{/each}
|
</svelte:fragment>
|
||||||
</div>
|
<svelte:fragment slot="full">
|
||||||
|
<FullCircle class="w-4 h-4 text-green-500" />
|
||||||
|
</svelte:fragment>
|
||||||
|
</Ratings>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
import FullShield from 'svelte-material-icons/Shield.svelte';
|
import FullShield from 'svelte-material-icons/Shield.svelte';
|
||||||
import ShieldHalfFullHalfEmpty from 'svelte-material-icons/ShieldHalfFull.svelte';
|
import ShieldHalfFullHalfEmpty from 'svelte-material-icons/ShieldHalfFull.svelte';
|
||||||
import ShieldEmpty from 'svelte-material-icons/ShieldOutline.svelte';
|
import ShieldEmpty from 'svelte-material-icons/ShieldOutline.svelte';
|
||||||
import ShieldHalfFull from 'svelte-material-icons/ShieldHalf.svelte';
|
|
||||||
|
|
||||||
export let health: number;
|
export let health: number;
|
||||||
export let maxHealth: number;
|
export let maxHealth: number;
|
||||||
|
|||||||
@@ -1,27 +1,41 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { getIdentityBackup } from '$lib/utils/';
|
import { getIdentityBackup } from '$lib/utils/';
|
||||||
|
|
||||||
|
$: id = getIdentityBackup();
|
||||||
|
$: identityBackupExists = id ? true : false;
|
||||||
|
$: encodedIdentity = 'data:text/json;charset=utf-8,' + encodeURIComponent(id!);
|
||||||
|
|
||||||
let revealIdentity = false;
|
let revealIdentity = false;
|
||||||
let id = '';
|
|
||||||
function reveal() {
|
function reveal() {
|
||||||
id = getIdentityBackup();
|
id = getIdentityBackup();
|
||||||
if (revealIdentity == false) {
|
if (id === undefined || id === null) {
|
||||||
revealIdentity = true;
|
id = 'No Identity Backup Found';
|
||||||
setTimeout(() => {
|
|
||||||
revealIdentity = false;
|
|
||||||
id = '';
|
|
||||||
}, 60000);
|
|
||||||
} else {
|
} else {
|
||||||
revealIdentity = false;
|
if (revealIdentity == false) {
|
||||||
|
revealIdentity = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
revealIdentity = false;
|
||||||
|
id = '';
|
||||||
|
}, 60000);
|
||||||
|
} else {
|
||||||
|
revealIdentity = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="m-2 sm:m-3 flex flex-col gap-4">
|
<div class="m-2 sm:m-3 flex flex-col gap-4">
|
||||||
<a
|
{#if identityBackupExists}
|
||||||
class="btn variant-ghost-success"
|
<a class="btn variant-ghost-success" href={encodedIdentity} download="Discreetly_Identity.json"
|
||||||
href={'data:text/json;charset=utf-8,' + encodeURIComponent(getIdentityBackup())}
|
>Download Identity Backup as JSON</a
|
||||||
download="Discreetly_Identity.json">Download Identity Backup as JSON</a
|
>
|
||||||
>
|
{:else}
|
||||||
|
<div class="text-sm text-primary-500">
|
||||||
|
Error getting your identity backup. Please contact the developers for help.
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if !revealIdentity}
|
{#if !revealIdentity}
|
||||||
<div class="btn variant-ghost-success" on:click={reveal}>Show Identity</div>
|
<div class="btn variant-ghost-success" on:click={reveal}>Show Identity</div>
|
||||||
{:else}
|
{:else}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import SelectServer from '$lib/components/SelectServer.svelte';
|
import SelectServer from '$lib/components/SelectServer.svelte';
|
||||||
|
import { alertAll } from '$lib/utils';
|
||||||
import { inviteCode } from '$lib/utils/inviteCode';
|
import { inviteCode } from '$lib/utils/inviteCode';
|
||||||
|
|
||||||
export let code = '';
|
export let code = '';
|
||||||
@@ -12,13 +13,13 @@
|
|||||||
inviteCode(code)
|
inviteCode(code)
|
||||||
.then(({ acceptedRoomNames, err }) => {
|
.then(({ acceptedRoomNames, err }) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
alert(err);
|
alertAll(err);
|
||||||
} else {
|
} else {
|
||||||
acceptedRoomNames = acceptedRoomNames;
|
acceptedRoomNames = acceptedRoomNames;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
alert(err);
|
alertAll(err);
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
loading = false;
|
loading = false;
|
||||||
|
|||||||
@@ -7,21 +7,23 @@
|
|||||||
import { getModalStore, type ModalSettings } from '@skeletonlabs/skeleton';
|
import { getModalStore, type ModalSettings } from '@skeletonlabs/skeleton';
|
||||||
import { deriveKey, hashPassword } from '$lib/crypto/crypto';
|
import { deriveKey, hashPassword } from '$lib/crypto/crypto';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { setPassword } from '$lib/utils';
|
import { alertAll, setPassword } from '$lib/utils';
|
||||||
|
|
||||||
const modalStore = getModalStore();
|
const modalStore = getModalStore();
|
||||||
|
|
||||||
export let cls: string = '';
|
export let cls: string = '';
|
||||||
|
|
||||||
|
let minPasswordLength = 3;
|
||||||
|
|
||||||
function setPasswordModal() {
|
function setPasswordModal() {
|
||||||
const modal: ModalSettings = {
|
const modal: ModalSettings = {
|
||||||
type: 'prompt',
|
type: 'prompt',
|
||||||
title: 'Set a Password',
|
title: 'Set a Password',
|
||||||
body: 'Set a password to encrypt your identity and room passwords',
|
body: 'Set a password or pin to encrypt your identity and room passwords',
|
||||||
value: '',
|
value: '',
|
||||||
valueAttr: { type: 'password', minlength: 3, required: true },
|
valueAttr: { type: 'password', minlength: minPasswordLength, required: true },
|
||||||
response: async (r: string) => {
|
response: async (r: string) => {
|
||||||
setPassword(r);
|
if (r != '' && r != null && r != undefined && r.length >= minPasswordLength) {
|
||||||
|
setPassword(r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
modalStore.trigger(modal);
|
modalStore.trigger(modal);
|
||||||
@@ -33,13 +35,14 @@
|
|||||||
title: 'Unlock',
|
title: 'Unlock',
|
||||||
body: 'Enter your password to unlock your keystores',
|
body: 'Enter your password to unlock your keystores',
|
||||||
value: '',
|
value: '',
|
||||||
valueAttr: { type: 'password', minlength: 3, required: true },
|
valueAttr: { type: 'password', minlength: 4, required: true },
|
||||||
response: async (r: string) => {
|
response: async (r: string) => {
|
||||||
if (r != 'false') {
|
if (r != 'false' && r != '' && r != null && r != undefined) {
|
||||||
const hashedPassword = await hashPassword(r);
|
const hashedPassword = await hashPassword(r);
|
||||||
if ($configStore.hashedPwd == hashedPassword) {
|
if ($configStore.hashedPwd == hashedPassword) {
|
||||||
$keyStore = await deriveKey(r);
|
$keyStore = await deriveKey(r);
|
||||||
} else {
|
} else {
|
||||||
|
alertAll('Incorrect Password');
|
||||||
$keyStore = null;
|
$keyStore = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,7 +56,7 @@
|
|||||||
}
|
}
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
console.debug(
|
console.debug(
|
||||||
'PasswordLock: ',
|
'PadLock:',
|
||||||
$passwordSet ? 'password set,' : 'password not set,',
|
$passwordSet ? 'password set,' : 'password not set,',
|
||||||
$keyStore !== null && $keyStore !== undefined ? 'unlocked' : 'locked'
|
$keyStore !== null && $keyStore !== undefined ? 'unlocked' : 'locked'
|
||||||
);
|
);
|
||||||
@@ -64,14 +67,14 @@
|
|||||||
{#if $passwordSet}
|
{#if $passwordSet}
|
||||||
{#if $keyStore instanceof CryptoKey}
|
{#if $keyStore instanceof CryptoKey}
|
||||||
<div on:click={lock} title="Unlocked, click to lock">
|
<div on:click={lock} title="Unlocked, click to lock">
|
||||||
<LockOpen class="text-warning-300-600-token" />
|
<LockOpen class="w-full text-warning-300-600-token" />
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div on:click={unlock} title="Locked" class="text-success-500"><Lock /></div>
|
<div on:click={unlock} title="Locked" class="w-full text-success-500"><Lock /></div>
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<div on:click={setPasswordModal} title="Password not set">
|
<div on:click={setPasswordModal} title="Password not set">
|
||||||
<NoPassword class="text-primary-500" />
|
<NoPassword class="w-full text-error-500" />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
24
src/lib/components/Welcome.svelte
Normal file
24
src/lib/components/Welcome.svelte
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Button from '$lib/components/button.svelte';
|
||||||
|
import { identityExists } from '$lib/stores';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if !$identityExists}
|
||||||
|
<p class="card py-2 px-4 md:px-5 mb-3">
|
||||||
|
If you have an <code class="code">invite code</code> head over to the <Button
|
||||||
|
link="/signup"
|
||||||
|
cls="variant-ghost-primary btn-sm m-2 sm:m-3">Sign Up</Button
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
<p class="card py-2 px-4 md:px-5">
|
||||||
|
Or if you want to request an invite code, join our <Button
|
||||||
|
link="https://discord.gg/brJQ36KVxk"
|
||||||
|
cls="variant-ghost-tertiary btn-sm m-2 sm:m-3">Discord</Button
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
{:else}
|
||||||
|
<p>
|
||||||
|
It looks like you are already signed up!
|
||||||
|
<Button link="/chat" cls="variant-ghost-success">Go Chat</Button>
|
||||||
|
</p>
|
||||||
|
{/if}
|
||||||
@@ -10,8 +10,11 @@ export const defaultServers = {
|
|||||||
|
|
||||||
export const configDefaults: ConfigurationI = {
|
export const configDefaults: ConfigurationI = {
|
||||||
signUpStatus: {
|
signUpStatus: {
|
||||||
inviteAccepted: false,
|
completedSignup: false,
|
||||||
identityBackedUp: false
|
identityBackedUp: false
|
||||||
},
|
},
|
||||||
identityStore: IdentityStoreE.NO_IDENTITY
|
identityStore: IdentityStoreE.NO_IDENTITY,
|
||||||
|
numMessagesToSave: 500,
|
||||||
|
hashedPwd: undefined,
|
||||||
|
beta: false
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,6 +23,14 @@ export async function getMessages(serverUrl: string, roomId: string) {
|
|||||||
return get([serverUrl, `api/room/${roomId}/messages`]) as Promise<MessageI[]>;
|
return get([serverUrl, `api/room/${roomId}/messages`]) as Promise<MessageI[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface CreateInviteData {
|
||||||
|
numCodes: number;
|
||||||
|
expiresAt?: number;
|
||||||
|
usesLeft?: number;
|
||||||
|
roomIds?: string[];
|
||||||
|
all?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export async function createInvite(
|
export async function createInvite(
|
||||||
serverUrl: string,
|
serverUrl: string,
|
||||||
username: string,
|
username: string,
|
||||||
@@ -32,7 +40,7 @@ export async function createInvite(
|
|||||||
expiresAt?: number,
|
expiresAt?: number,
|
||||||
usesLeft?: number
|
usesLeft?: number
|
||||||
) {
|
) {
|
||||||
const data = { numCodes, expiresAt, usesLeft };
|
const data: CreateInviteData = { numCodes, expiresAt, usesLeft };
|
||||||
if (roomIds.length > 0) {
|
if (roomIds.length > 0) {
|
||||||
data['roomIds'] = roomIds;
|
data['roomIds'] = roomIds;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -129,3 +129,14 @@ export const identityStore = storable({} as IdentityStoreI, 'identity');
|
|||||||
* @description Identity store, this is the user's identity ENCRYPTED
|
* @description Identity store, this is the user's identity ENCRYPTED
|
||||||
*/
|
*/
|
||||||
export const identityKeyStore = encryptable({} as IdentityStoreI, 'identityencrypted');
|
export const identityKeyStore = encryptable({} as IdentityStoreI, 'identityencrypted');
|
||||||
|
|
||||||
|
export const identityExists = derived(
|
||||||
|
[identityStore, identityKeyStore],
|
||||||
|
([$identityStore, $identityKeyStore]) => {
|
||||||
|
if ($identityStore._commitment || $identityKeyStore._commitment) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export enum Experiences {
|
|||||||
export enum IdentityStoreE {
|
export enum IdentityStoreE {
|
||||||
'NO_IDENTITY',
|
'NO_IDENTITY',
|
||||||
'localStorage',
|
'localStorage',
|
||||||
|
'localStorageEncrypted',
|
||||||
'cryptKeeper',
|
'cryptKeeper',
|
||||||
'PCDPass'
|
'PCDPass'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,10 +36,8 @@ export interface JoinResponseI {
|
|||||||
roomIds: string[];
|
roomIds: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keyed by roomId
|
|
||||||
|
|
||||||
export interface SignUpStatusI {
|
export interface SignUpStatusI {
|
||||||
inviteAccepted: boolean;
|
completedSignup: boolean;
|
||||||
identityBackedUp: boolean;
|
identityBackedUp: boolean;
|
||||||
inviteCode?: string;
|
inviteCode?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,3 +30,12 @@ export const clearConsoleMessages = () => {
|
|||||||
return newState;
|
return newState;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function isInputFieldFocused() {
|
||||||
|
const activeElement = document.activeElement;
|
||||||
|
return (
|
||||||
|
activeElement &&
|
||||||
|
(activeElement.tagName.toLowerCase() === 'input' ||
|
||||||
|
activeElement.tagName.toLowerCase() === 'textarea')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -65,35 +65,35 @@ export function getIdentity(): IdentityStoreI {
|
|||||||
|
|
||||||
export function getCommitment() {
|
export function getCommitment() {
|
||||||
const id = get(identityKeyStore) as IdentityStoreI;
|
const id = get(identityKeyStore) as IdentityStoreI;
|
||||||
const id_old = get(identityStore);
|
const id_ = get(identityStore);
|
||||||
if (id !== null && id !== undefined) {
|
if (id !== null && id !== undefined) {
|
||||||
return id._commitment;
|
return id._commitment;
|
||||||
}
|
}
|
||||||
if (id_old !== null && id_old !== undefined) {
|
if (id_ !== null && id_ !== undefined) {
|
||||||
console.warn('PLEASE ADD A PASSWORD!');
|
console.warn('PLEASE ADD A PASSWORD!');
|
||||||
return id_old._commitment;
|
return id_._commitment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getIdentityBackup() {
|
export function getIdentityBackup() {
|
||||||
const id = get(identityKeyStore);
|
const id = get(identityKeyStore);
|
||||||
const id_old = get(identityStore);
|
const id_ = get(identityStore);
|
||||||
if (id !== null && id !== undefined) {
|
if (id !== null && id !== undefined) {
|
||||||
return JSON.stringify(id);
|
return JSON.stringify(id);
|
||||||
}
|
}
|
||||||
if (id_old !== null && id_old !== undefined) {
|
if (id_ !== null && id_ !== undefined) {
|
||||||
console.warn('PLEASE ADD A PASSWORD!');
|
console.warn('PLEASE ADD A PASSWORD!');
|
||||||
return JSON.stringify(id_old);
|
return JSON.stringify(id_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doesIdentityExist(): 'safe' | 'unsafe' | 'none' {
|
export function doesIdentityExist(): 'safe' | 'unsafe' | 'none' {
|
||||||
const id = get(identityKeyStore);
|
const id = get(identityKeyStore);
|
||||||
const id_old = get(identityStore);
|
const id_ = get(identityStore);
|
||||||
if (id._commitment !== null && id._commitment !== undefined) {
|
if (id._commitment !== null && id._commitment !== undefined) {
|
||||||
return 'safe';
|
return 'safe';
|
||||||
}
|
}
|
||||||
if (id_old._commitment !== null && id_old._commitment !== undefined) {
|
if (id_._commitment !== null && id_._commitment !== undefined) {
|
||||||
console.warn('PLEASE ADD A PASSWORD');
|
console.warn('PLEASE ADD A PASSWORD');
|
||||||
return 'unsafe';
|
return 'unsafe';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { getCommitment, updateRooms } from '$lib/utils/';
|
import { alertAll, getCommitment, updateRooms } from '$lib/utils/';
|
||||||
import { postInviteCode } from '$lib/services/server';
|
import { postInviteCode } from '$lib/services/server';
|
||||||
import { selectedServer, configStore } from '$lib/stores';
|
import { selectedServer, configStore } from '$lib/stores';
|
||||||
import { get } from 'svelte/store';
|
import { get } from 'svelte/store';
|
||||||
@@ -10,6 +10,11 @@ export async function inviteCode(newCode: string) {
|
|||||||
const server = get(selectedServer);
|
const server = get(selectedServer);
|
||||||
try {
|
try {
|
||||||
const idc = getCommitment();
|
const idc = getCommitment();
|
||||||
|
if (!idc) {
|
||||||
|
// TODO convert this to alertAll at some point
|
||||||
|
alertAll('No identity commitment found');
|
||||||
|
throw new Error('No identity commitment found');
|
||||||
|
}
|
||||||
const result = (await postInviteCode(server, {
|
const result = (await postInviteCode(server, {
|
||||||
code: newCode.toLowerCase(),
|
code: newCode.toLowerCase(),
|
||||||
idc
|
idc
|
||||||
@@ -20,7 +25,7 @@ export async function inviteCode(newCode: string) {
|
|||||||
acceptedRoomNames = await updateRooms(server, result.roomIds);
|
acceptedRoomNames = await updateRooms(server, result.roomIds);
|
||||||
console.log(`Added to rooms: ${acceptedRoomNames}`);
|
console.log(`Added to rooms: ${acceptedRoomNames}`);
|
||||||
configStore.update((store) => {
|
configStore.update((store) => {
|
||||||
store['signUpStatus']['inviteAccepted'] = true;
|
store['signUpStatus']['completedSignup'] = true;
|
||||||
store['signUpStatus']['inviteCode'] = '';
|
store['signUpStatus']['inviteCode'] = '';
|
||||||
return store;
|
return store;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,9 +20,11 @@ export function getEpochFromTimestamp(
|
|||||||
let relative = '';
|
let relative = '';
|
||||||
try {
|
try {
|
||||||
relative = formatRelative(new Date(timestamp), new Date());
|
relative = formatRelative(new Date(timestamp), new Date());
|
||||||
} catch (err) {
|
} catch (err: unknown) {
|
||||||
|
let message = 'Unknown Error';
|
||||||
|
if (err instanceof Error) message = err.message;
|
||||||
relative = 'Unknown';
|
relative = 'Unknown';
|
||||||
console.debug(`${err.message}: ${epoch} * ${ratelimit} = ${timestamp}`);
|
console.debug(`${message}: ${epoch} * ${ratelimit} = ${timestamp}`);
|
||||||
}
|
}
|
||||||
return { epoch, relative, timestamp };
|
return { epoch, relative, timestamp };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,11 @@ function updateRoomStore(rooms: RoomI[], serverURL: string = get(selectedServer)
|
|||||||
async function getRoomIdsIfEmpty(server: string, roomIds: string[]): Promise<string[]> {
|
async function getRoomIdsIfEmpty(server: string, roomIds: string[]): Promise<string[]> {
|
||||||
if (roomIds.length < 1) {
|
if (roomIds.length < 1) {
|
||||||
const idc = getCommitment();
|
const idc = getCommitment();
|
||||||
|
if (!idc) {
|
||||||
|
// TODO convert this to alertAll at some point
|
||||||
|
console.error('No identity commitment found');
|
||||||
|
throw new Error('No identity commitment found');
|
||||||
|
}
|
||||||
return await getRoomIdsByIdentityCommitment(server, idc);
|
return await getRoomIdsByIdentityCommitment(server, idc);
|
||||||
}
|
}
|
||||||
return roomIds;
|
return roomIds;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { get, type Writable } from 'svelte/store';
|
import { get, type Writable } from 'svelte/store';
|
||||||
import type { serverStoreI } from '../stores';
|
import type { serverStoreI } from '../types/stores';
|
||||||
import { serverStore, roomsStore, selectedServer } from '../stores';
|
import { serverStore, roomsStore, selectedServer } from '../stores';
|
||||||
import { getServerData } from '$lib/services/server';
|
import { getServerData } from '$lib/services/server';
|
||||||
import type { RoomI } from '$lib/types';
|
import type { RoomI } from '$lib/types';
|
||||||
@@ -19,7 +19,7 @@ export function getServerRooms(url: string, store: Writable<serverStoreI> = serv
|
|||||||
if (!roomIds) {
|
if (!roomIds) {
|
||||||
roomIds = [];
|
roomIds = [];
|
||||||
}
|
}
|
||||||
return roomIds.map((roomId) => {
|
return roomIds.map((roomId: string) => {
|
||||||
return get(roomsStore)[roomId];
|
return get(roomsStore)[roomId];
|
||||||
}) as RoomI[];
|
}) as RoomI[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { AppShell, Modal, initializeStores } from '@skeletonlabs/skeleton';
|
import { Modal, initializeStores } from '@skeletonlabs/skeleton';
|
||||||
import { Toast } from '@skeletonlabs/skeleton';
|
import { Toast } from '@skeletonlabs/skeleton';
|
||||||
import '../app.postcss';
|
import '../app.postcss';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import AppHeader from './AppHeader.svelte';
|
import AppHeader from './AppHeader.svelte';
|
||||||
import Loading from '$lib/components/loading.svelte';
|
import Loading from '$lib/components/loading.svelte';
|
||||||
import { selectedServer } from '$lib/stores';
|
import { selectedServer } from '$lib/stores';
|
||||||
import { getServerList, setDefaultServers } from '$lib/utils/';
|
import { getServerList, isInputFieldFocused, setDefaultServers } from '$lib/utils/';
|
||||||
import { updateServer } from '$lib/utils/';
|
import { updateServer } from '$lib/utils/';
|
||||||
import { Drawer } from '@skeletonlabs/skeleton';
|
import { Drawer, getDrawerStore } from '@skeletonlabs/skeleton';
|
||||||
import SelectServer from '$lib/components/SelectServer.svelte';
|
import SelectServer from '$lib/components/SelectServer.svelte';
|
||||||
import SelectRoom from '$lib/components/SelectRoom.svelte';
|
import SelectRoom from '$lib/components/SelectRoom.svelte';
|
||||||
|
import Console from './console/Console.svelte';
|
||||||
|
import Sidebar from './Sidebar.svelte';
|
||||||
|
import AppFooter from './AppFooter.svelte';
|
||||||
|
|
||||||
initializeStores();
|
initializeStores();
|
||||||
|
|
||||||
|
const drawerStore = getDrawerStore();
|
||||||
// Hack to get BigInt <-> JSON compatibility
|
// Hack to get BigInt <-> JSON compatibility
|
||||||
(BigInt.prototype as any).toJSON = function () {
|
(BigInt.prototype as any).toJSON = function () {
|
||||||
return this.toString();
|
return this.toString();
|
||||||
@@ -25,19 +29,48 @@
|
|||||||
setDefaultServers();
|
setDefaultServers();
|
||||||
}
|
}
|
||||||
updateServer($selectedServer);
|
updateServer($selectedServer);
|
||||||
|
document.addEventListener('keydown', function (event) {
|
||||||
|
if (event.key === '`') {
|
||||||
|
if (!isInputFieldFocused()) {
|
||||||
|
event.preventDefault();
|
||||||
|
if ($drawerStore.open !== true) {
|
||||||
|
drawerStore.open({ id: 'console' });
|
||||||
|
} else {
|
||||||
|
drawerStore.close();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Input field focused, not opening console');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Modal />
|
<Modal />
|
||||||
<Toast position="t" background="variant-filled-primary" />
|
<Toast position="t" background="variant-filled-primary" />
|
||||||
<Drawer position="top" padding="p-4" rounded="rounded-token">
|
<Drawer position="top" padding="p-4" rounded="rounded-token">
|
||||||
<SelectServer />
|
{#if $drawerStore.id === 'roomselect'}
|
||||||
<SelectRoom />
|
<SelectServer />
|
||||||
|
<SelectRoom />
|
||||||
|
{:else if $drawerStore.id === 'console'}
|
||||||
|
<Console />
|
||||||
|
{/if}
|
||||||
</Drawer>
|
</Drawer>
|
||||||
|
|
||||||
<AppShell>
|
<div class="w-full h-screen flex flex-col overflow-hidden">
|
||||||
<svelte:fragment slot="header"><AppHeader /></svelte:fragment>
|
<div class="flex-none z-10"><AppHeader /></div>
|
||||||
<slot>
|
<div class="grid grid-cols-[1fr,auto] h-full min-w-full justify-between">
|
||||||
<Loading />
|
<main class="flex flex-col justify-between">
|
||||||
</slot>
|
<slot class="flex flex-col justify-center">
|
||||||
</AppShell>
|
<Loading />
|
||||||
|
</slot>
|
||||||
|
<div class="block lg:hidden">
|
||||||
|
<AppFooter />
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<div class="hidden lg:block"><Sidebar /></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Button from '$lib/components/button.svelte';
|
import Welcome from '$lib/components/Welcome.svelte';
|
||||||
import { identityStore } from '$lib/stores';
|
|
||||||
$: identityExists = !!$identityStore._commitment;
|
|
||||||
|
|
||||||
console.info(
|
console.info(
|
||||||
'I see you are checking out the logs, let us know what you think on our discord: https://discord.gg/brJQ36KVxk'
|
'I see you are checking out the logs, let us know what you think on our discord: https://discord.gg/brJQ36KVxk'
|
||||||
@@ -10,21 +8,6 @@
|
|||||||
|
|
||||||
<div class="mx-5 lg:mx-auto mt-10 max-w-[80ch]">
|
<div class="mx-5 lg:mx-auto mt-10 max-w-[80ch]">
|
||||||
<h2 class="h2 mb-5">Welcome to Discreetly!</h2>
|
<h2 class="h2 mb-5">Welcome to Discreetly!</h2>
|
||||||
{#if !identityExists}
|
<Welcome />
|
||||||
<p class="card py-2 px-4 md:px-5 mb-3">
|
|
||||||
If you have an <code class="code">invite code</code> head over to the <Button
|
|
||||||
link="/signup"
|
|
||||||
cls="variant-ghost-primary btn-sm m-2 sm:m-3">Sign Up</Button
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
<p class="card py-2 px-4 md:px-5">
|
|
||||||
Or if you want to request an invite code, join our <Button
|
|
||||||
link="https://discord.gg/brJQ36KVxk"
|
|
||||||
cls="variant-ghost-tertiary btn-sm m-2 sm:m-3">Discord</Button
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
{:else}
|
|
||||||
<Button link="/chat" cls="variant-ghost-success">Go Chat</Button>
|
|
||||||
{/if}
|
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,27 +1,97 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { identityStore } from '$lib/stores';
|
import { page } from '$app/stores';
|
||||||
import { AppBar } from '@skeletonlabs/skeleton';
|
import { passwordSet, configStore, keyStore } from '$lib/stores';
|
||||||
$: identityExists = !!$identityStore._commitment;
|
import { getModalStore, type ModalSettings } from '@skeletonlabs/skeleton';
|
||||||
|
import { deriveKey, hashPassword } from '$lib/crypto/crypto';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import { TabAnchor, TabGroup } from '@skeletonlabs/skeleton';
|
||||||
|
|
||||||
|
import Chat from 'svelte-material-icons/Chat.svelte';
|
||||||
|
import Settings from 'svelte-material-icons/TuneVariant.svelte';
|
||||||
|
import Information from 'svelte-material-icons/Information.svelte';
|
||||||
|
import Lock from 'svelte-material-icons/Lock.svelte';
|
||||||
|
import LockOpen from 'svelte-material-icons/LockOpenVariant.svelte';
|
||||||
|
import NoPassword from 'svelte-material-icons/LockOff.svelte';
|
||||||
|
import { alertAll } from '$lib/utils';
|
||||||
|
|
||||||
|
const modalStore = getModalStore();
|
||||||
|
|
||||||
|
function unlock() {
|
||||||
|
const modal: ModalSettings = {
|
||||||
|
type: 'prompt',
|
||||||
|
title: 'Unlock',
|
||||||
|
body: 'Enter your password to unlock your keystores',
|
||||||
|
value: '',
|
||||||
|
valueAttr: { type: 'password', minlength: 4, required: true },
|
||||||
|
response: async (r: string) => {
|
||||||
|
if (r != 'false' && r != '' && r != null && r != undefined) {
|
||||||
|
const hashedPassword = await hashPassword(r);
|
||||||
|
if ($configStore.hashedPwd == hashedPassword) {
|
||||||
|
$keyStore = await deriveKey(r);
|
||||||
|
} else {
|
||||||
|
alertAll('Incorrect Password');
|
||||||
|
$keyStore = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
modalStore.trigger(modal);
|
||||||
|
}
|
||||||
|
|
||||||
|
function lock() {
|
||||||
|
$keyStore = null;
|
||||||
|
}
|
||||||
|
onMount(() => {
|
||||||
|
console.debug(
|
||||||
|
'PadLock:',
|
||||||
|
$passwordSet ? 'password set,' : 'password not set,',
|
||||||
|
$keyStore !== null && $keyStore !== undefined ? 'unlocked' : 'locked'
|
||||||
|
);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<AppBar class="hidden md:block" padding="py-3 px-8">
|
<TabGroup
|
||||||
<svelte:fragment slot="lead">
|
justify="justify-center"
|
||||||
<a href="/">Home</a>
|
active="variant-filled-primary"
|
||||||
{#if identityExists}
|
hover="hover:variant-soft-primary"
|
||||||
<a href="/chat">Chat</a>
|
flex="flex-1 lg:flex-none"
|
||||||
{:else}
|
class="bg-surface-100-800-token w-full"
|
||||||
<a href="/signup">Sign Up</a>
|
>
|
||||||
{/if}
|
<TabAnchor href="/about" selected={$page.url.pathname === '/about'} title="About">
|
||||||
<a href="/about">About</a>
|
<svelte:fragment slot="lead"><Information class="rail-icon" /></svelte:fragment>
|
||||||
</svelte:fragment>
|
<span>About</span>
|
||||||
<svelte:fragment slot="trail">
|
</TabAnchor>
|
||||||
<p class="hidden sm:inline me-2 text-primary-500">Alpha Version!</p>
|
|
||||||
<p><a href="/testing" style="margin:0 !important">© 2023 Privacy & Scaling Explorations</a></p>
|
|
||||||
</svelte:fragment>
|
|
||||||
</AppBar>
|
|
||||||
|
|
||||||
<style>
|
<TabAnchor href="/chat" selected={$page.url.pathname === '/chat'} title="Chat">
|
||||||
a {
|
<svelte:fragment slot="lead"><Chat class="rail-icon" /></svelte:fragment>
|
||||||
margin-right: 1.5rem;
|
<span>Chat</span>
|
||||||
}
|
</TabAnchor>
|
||||||
</style>
|
{#if $passwordSet}
|
||||||
|
{#if $keyStore instanceof CryptoKey}
|
||||||
|
<TabAnchor on:click={lock} title="Unlocked, click to lock">
|
||||||
|
<svelte:fragment slot="lead">
|
||||||
|
<LockOpen class="rail-icon text-warning-300-600-token" />
|
||||||
|
</svelte:fragment>
|
||||||
|
<span>Lock</span>
|
||||||
|
</TabAnchor>
|
||||||
|
{:else}
|
||||||
|
<TabAnchor on:click={unlock} title="Locked">
|
||||||
|
<svelte:fragment slot="lead">
|
||||||
|
<Lock class="rail-icon text-success-500" />
|
||||||
|
</svelte:fragment>
|
||||||
|
<span>Unlock</span>
|
||||||
|
</TabAnchor>
|
||||||
|
{/if}
|
||||||
|
{:else}
|
||||||
|
<TabAnchor href="/settings/security" title="Password not set">
|
||||||
|
<svelte:fragment slot="lead">
|
||||||
|
<NoPassword class="rail-icon text-error-500" />
|
||||||
|
</svelte:fragment>
|
||||||
|
<span>Secure</span>
|
||||||
|
</TabAnchor>
|
||||||
|
{/if}
|
||||||
|
<TabAnchor href="/settings" selected={$page.url.pathname === '/settings'} title="Settings">
|
||||||
|
<svelte:fragment slot="lead"><Settings class="rail-icon" /></svelte:fragment>
|
||||||
|
<span>Settings</span>
|
||||||
|
</TabAnchor>
|
||||||
|
</TabGroup>
|
||||||
|
|||||||
@@ -1,21 +1,17 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { AppBar } from '@skeletonlabs/skeleton';
|
import { AppBar, type DrawerSettings } from '@skeletonlabs/skeleton';
|
||||||
import { LightSwitch } from '@skeletonlabs/skeleton';
|
import { currentSelectedRoom, identityExists } from '$lib/stores';
|
||||||
import { page } from '$app/stores';
|
|
||||||
import { configStore, currentSelectedRoom, identityStore, keyStore } from '$lib/stores';
|
|
||||||
import { getDrawerStore } from '@skeletonlabs/skeleton';
|
import { getDrawerStore } from '@skeletonlabs/skeleton';
|
||||||
import Settings from 'svelte-material-icons/TuneVariant.svelte';
|
|
||||||
import Information from 'svelte-material-icons/Information.svelte';
|
|
||||||
import Console from 'svelte-material-icons/Console.svelte';
|
|
||||||
import PasswordLock from '$lib/components/Padlock.svelte';
|
|
||||||
import Chat from 'svelte-material-icons/Chat.svelte';
|
|
||||||
$: identityExists = !!$identityStore._commitment;
|
|
||||||
$: roomName = $currentSelectedRoom?.name ?? 'Select Room';
|
$: roomName = $currentSelectedRoom?.name ?? 'Select Room';
|
||||||
|
|
||||||
const drawerStore = getDrawerStore();
|
const drawerStore = getDrawerStore();
|
||||||
|
|
||||||
|
const settings: DrawerSettings = { id: 'roomselect' };
|
||||||
|
|
||||||
// Open the drawer:
|
// Open the drawer:
|
||||||
function drawerOpen(): void {
|
function drawerOpen(): void {
|
||||||
drawerStore.open();
|
drawerStore.open(settings);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -29,43 +25,43 @@
|
|||||||
>
|
>
|
||||||
<svelte:fragment slot="lead">
|
<svelte:fragment slot="lead">
|
||||||
<h1 class="h4 text-primary-500">
|
<h1 class="h4 text-primary-500">
|
||||||
{#if identityExists}
|
{#if $identityExists}
|
||||||
<a href="/chat"><img class="max-h-7" src="/logo-text.png" alt="discreetly" /></a>
|
<a href="/chat" role="button" tabindex="0"
|
||||||
|
><img class="max-h-7" src="/logo-text.png" alt="discreetly" /></a
|
||||||
|
>
|
||||||
{:else}
|
{:else}
|
||||||
<a href="/"><img class="max-h-7" src="/logo-text.png" alt="discreetly" /></a>
|
<a href="/" role="button" tabindex="0"
|
||||||
|
><img class="max-h-7" src="/logo-text.png" alt="discreetly" /></a
|
||||||
|
>
|
||||||
{/if}
|
{/if}
|
||||||
</h1>
|
</h1>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
|
|
||||||
<a href="/about" class="btn btn-sm variant-ringed-secondary hidden sm:inline">About</a>
|
{#if $identityExists}
|
||||||
{#if identityExists}
|
<a
|
||||||
<a href="/chat" class="hidden btn btn-sm variant-ringed-secondary sm:inline">Chat</a>
|
href="/chat"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
class="hidden btn btn-sm variant-ringed-secondary sm:inline">Chat</a
|
||||||
|
>
|
||||||
|
<!-- svelte-ignore a11y-missing-attribute -->
|
||||||
<a
|
<a
|
||||||
class="btn btn-sm variant-ringed-secondary font-medium text-sm inline sm:hidden"
|
class="btn btn-sm variant-ringed-secondary font-medium text-sm inline sm:hidden"
|
||||||
on:click={drawerOpen}>{roomName}</a
|
on:click={drawerOpen}
|
||||||
|
on:keypress={() => {
|
||||||
|
drawerOpen();
|
||||||
|
}}
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
>
|
>
|
||||||
|
{roomName}
|
||||||
|
</a>
|
||||||
{:else}
|
{:else}
|
||||||
<a class="btn btn-sm variant-ringed-secondary" href="/signup">Sign Up</a>
|
<a class="btn btn-sm variant-ringed-secondary" href="/signup" role="button" tabindex="0"
|
||||||
|
>Sign Up</a
|
||||||
|
>
|
||||||
{/if}
|
{/if}
|
||||||
<a
|
|
||||||
class="btn btn-sm variant-ringed-secondary font-medium text-sm hidden sm:inline"
|
|
||||||
href="/console">Console</a
|
|
||||||
>
|
|
||||||
<svelte:fragment slot="trail">
|
<svelte:fragment slot="trail">
|
||||||
<a href="/about" class="hidden sm:inline"><Information size="1.2em" /></a>
|
<div class="hidden sm:inline text-primary-500">Alpha Version!</div>
|
||||||
{#if identityExists && $page.url.pathname !== '/chat'}
|
|
||||||
<a href="/chat" class="inline"><Chat size="1.2em" /></a>
|
|
||||||
{/if}
|
|
||||||
{#if $page.url.pathname !== '/console'}
|
|
||||||
<a href="/console" class="inline"><Console size="1.2em" /></a>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<PasswordLock cls="inline" />
|
|
||||||
{#if identityExists}
|
|
||||||
<a href="/settings"><Settings size="1.2em" /></a>
|
|
||||||
{/if}
|
|
||||||
<div class="hidden sm:inline">
|
|
||||||
<LightSwitch />
|
|
||||||
</div>
|
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</AppBar>
|
</AppBar>
|
||||||
|
|||||||
104
src/routes/Sidebar.svelte
Normal file
104
src/routes/Sidebar.svelte
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { page } from '$app/stores';
|
||||||
|
import {
|
||||||
|
AppRail,
|
||||||
|
AppRailAnchor,
|
||||||
|
getModalStore,
|
||||||
|
type ModalSettings
|
||||||
|
} from '@skeletonlabs/skeleton';
|
||||||
|
import Chat from 'svelte-material-icons/Chat.svelte';
|
||||||
|
import Settings from 'svelte-material-icons/TuneVariant.svelte';
|
||||||
|
import Information from 'svelte-material-icons/Information.svelte';
|
||||||
|
import Console from 'svelte-material-icons/Console.svelte';
|
||||||
|
import Lock from 'svelte-material-icons/Lock.svelte';
|
||||||
|
import LockOpen from 'svelte-material-icons/LockOpenVariant.svelte';
|
||||||
|
import NoPassword from 'svelte-material-icons/LockOff.svelte';
|
||||||
|
import { hashPassword, deriveKey } from '$lib/crypto/crypto';
|
||||||
|
import { configStore, keyStore, passwordSet } from '$lib/stores';
|
||||||
|
import { alertAll } from '$lib/utils';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
|
const modalStore = getModalStore();
|
||||||
|
|
||||||
|
function unlock() {
|
||||||
|
const modal: ModalSettings = {
|
||||||
|
type: 'prompt',
|
||||||
|
title: 'Unlock',
|
||||||
|
body: 'Enter your password to unlock your keystores',
|
||||||
|
value: '',
|
||||||
|
valueAttr: { type: 'password', minlength: 4, required: true },
|
||||||
|
response: async (r: string) => {
|
||||||
|
if (r != 'false' && r != '' && r != null && r != undefined) {
|
||||||
|
const hashedPassword = await hashPassword(r);
|
||||||
|
if ($configStore.hashedPwd == hashedPassword) {
|
||||||
|
$keyStore = await deriveKey(r);
|
||||||
|
} else {
|
||||||
|
alertAll('Incorrect Password');
|
||||||
|
$keyStore = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
modalStore.trigger(modal);
|
||||||
|
}
|
||||||
|
|
||||||
|
function lock() {
|
||||||
|
$keyStore = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
console.debug(
|
||||||
|
'PadLock:',
|
||||||
|
$passwordSet ? 'password set,' : 'password not set,',
|
||||||
|
$keyStore !== null && $keyStore !== undefined ? 'unlocked' : 'locked'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<AppRail height="h-full">
|
||||||
|
<AppRailAnchor href="/chat" selected={$page.url.pathname === '/chat'} title="Chat">
|
||||||
|
<svelte:fragment slot="lead"><Chat class="rail-icon" /></svelte:fragment>
|
||||||
|
<span>Chat</span>
|
||||||
|
</AppRailAnchor>
|
||||||
|
|
||||||
|
<AppRailAnchor href="/about" selected={$page.url.pathname === '/about'} title="About">
|
||||||
|
<svelte:fragment slot="lead"><Information class="rail-icon" /></svelte:fragment>
|
||||||
|
<span>About</span>
|
||||||
|
</AppRailAnchor>
|
||||||
|
|
||||||
|
<AppRailAnchor href="/console" selected={$page.url.pathname === '/console'} title="About">
|
||||||
|
<svelte:fragment slot="lead"><Console class="rail-icon" /></svelte:fragment>
|
||||||
|
<span>Console</span>
|
||||||
|
</AppRailAnchor>
|
||||||
|
|
||||||
|
<svelte:fragment slot="trail">
|
||||||
|
{#if $passwordSet}
|
||||||
|
{#if $keyStore instanceof CryptoKey}
|
||||||
|
<AppRailAnchor on:click={lock} title="Unlocked, click to lock">
|
||||||
|
<svelte:fragment slot="lead">
|
||||||
|
<LockOpen class="rail-icon text-warning-300-600-token" />
|
||||||
|
</svelte:fragment>
|
||||||
|
<span>Lock</span>
|
||||||
|
</AppRailAnchor>
|
||||||
|
{:else}
|
||||||
|
<AppRailAnchor on:click={unlock} title="Locked">
|
||||||
|
<svelte:fragment slot="lead">
|
||||||
|
<Lock class="rail-icon text-success-500" />
|
||||||
|
</svelte:fragment>
|
||||||
|
<span>Unlock</span>
|
||||||
|
</AppRailAnchor>
|
||||||
|
{/if}
|
||||||
|
{:else}
|
||||||
|
<AppRailAnchor href="/settings/security" title="Password not set">
|
||||||
|
<svelte:fragment slot="lead">
|
||||||
|
<NoPassword class="rail-icon text-error-500" />
|
||||||
|
</svelte:fragment>
|
||||||
|
<span>Secure</span>
|
||||||
|
</AppRailAnchor>
|
||||||
|
{/if}
|
||||||
|
<AppRailAnchor href="/settings" selected={$page.url.pathname === '/settings'} title="Settings">
|
||||||
|
<svelte:fragment slot="lead"><Settings class="rail-icon" /></svelte:fragment>
|
||||||
|
<span>Settings</span>
|
||||||
|
</AppRailAnchor>
|
||||||
|
</svelte:fragment>
|
||||||
|
</AppRail>
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { identityStore, serverStore } from '$lib/stores';
|
import { identityExists, serverStore } from '$lib/stores';
|
||||||
import { updateServer } from '$lib/utils';
|
import { updateServer } from '$lib/utils';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
$: identityExists = !!$identityStore._commitment;
|
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
if (!identityExists) {
|
if (!$identityExists) {
|
||||||
goto('/signup');
|
goto('/signup');
|
||||||
}
|
}
|
||||||
if (!Object.keys($serverStore).length) {
|
if (!Object.keys($serverStore).length) {
|
||||||
|
|||||||
@@ -2,4 +2,6 @@
|
|||||||
import Console from './Console.svelte';
|
import Console from './Console.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Console />
|
<div class="mx-2 h-full">
|
||||||
|
<Console />
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -3,30 +3,39 @@
|
|||||||
import { consoleStore } from '$lib/stores';
|
import { consoleStore } from '$lib/stores';
|
||||||
import { clearConsoleMessages } from '$lib/utils';
|
import { clearConsoleMessages } from '$lib/utils';
|
||||||
import TrashCan from 'svelte-material-icons/TrashCanOutline.svelte';
|
import TrashCan from 'svelte-material-icons/TrashCanOutline.svelte';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
let elemChat: HTMLElement;
|
||||||
export let placeholder: string = 'Enter / Command';
|
export let placeholder: string = 'Enter / Command';
|
||||||
|
|
||||||
|
function scrollChatBottom(behavior?: ScrollBehavior): void {
|
||||||
|
setTimeout(() => {
|
||||||
|
elemChat.scrollTo({ top: elemChat.scrollHeight, behavior });
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
scrollChatBottom('smooth');
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="mx-3 my-2">
|
<div class="p-4 small:p-2 h-full overflow-y-hidden grid grid-rows-[auto,1fr,auto]">
|
||||||
<h3 class="h3 mb-1 small:mb-3">Console</h3>
|
<header class="flex flex-row justify-between px-2">
|
||||||
<div class="card variant-ghost-surface">
|
<h6 class="h4">Console</h6>
|
||||||
<header class="card-header">
|
<button
|
||||||
<button
|
class="btn btn-sm variant-ghost-primary float-right"
|
||||||
class="btn btn-sm variant-ghost-primary float-right"
|
on:click={() => clearConsoleMessages()}
|
||||||
on:click={() => clearConsoleMessages()}
|
>
|
||||||
>
|
<TrashCan />
|
||||||
<TrashCan />
|
</button>
|
||||||
</button>
|
</header>
|
||||||
</header>
|
<section class="p-4 overflow-y-scroll" bind:this={elemChat}>
|
||||||
<section class="p-4">
|
{#each $consoleStore.messages as line, idx}
|
||||||
{#each $consoleStore.messages as line, idx}
|
<p class={line.type}>{line.message}</p>
|
||||||
<p class={line.type}>{line.message}</p>
|
{/each}
|
||||||
{/each}
|
</section>
|
||||||
</section>
|
<footer>
|
||||||
<footer class="card-footer">
|
<InputPrompt {placeholder} />
|
||||||
<InputPrompt {placeholder} />
|
</footer>
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
addConsoleMessage('`/clear` Clears the console');
|
addConsoleMessage('`/clear` Clears the console');
|
||||||
addConsoleMessage('`/join invite-code` Joins a room via invite code, Example:');
|
addConsoleMessage('`/join invite-code` Joins a room via invite code, Example:');
|
||||||
addConsoleMessage('`/password Password`');
|
addConsoleMessage('`/password Password`');
|
||||||
addConsoleMessage('`/clearPassword`');
|
|
||||||
addConsoleMessage('`/unlock Password`');
|
addConsoleMessage('`/unlock Password`');
|
||||||
addConsoleMessage('`/lock`');
|
addConsoleMessage('`/lock`');
|
||||||
addConsoleMessage('`/backup`');
|
addConsoleMessage('`/backup`');
|
||||||
@@ -75,10 +74,6 @@
|
|||||||
addConsoleMessage('/password OLDPASSWORD NEWPASSWORD', 'warning');
|
addConsoleMessage('/password OLDPASSWORD NEWPASSWORD', 'warning');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '/clearPassword':
|
|
||||||
$configStore.hashedPwd = null;
|
|
||||||
addConsoleMessage('Password Cleared');
|
|
||||||
break;
|
|
||||||
case '/lock':
|
case '/lock':
|
||||||
$keyStore = null;
|
$keyStore = null;
|
||||||
addConsoleMessage('Locked!');
|
addConsoleMessage('Locked!');
|
||||||
|
|||||||
5
src/routes/gateways/+page.svelte
Normal file
5
src/routes/gateways/+page.svelte
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import JoinMore from './JoinMore.svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<JoinMore />
|
||||||
@@ -1,7 +1,3 @@
|
|||||||
<div class=" mx-2 md:mx-4">
|
<div class="px-2 sm:px-5 mt-3 sm:mt-8 overflow-scroll h-100">
|
||||||
<div class="mx-auto mt-10 max-w-[80ch]">
|
<slot />
|
||||||
<h2 class="h2 mb-8 text-center">Manage Your Identity</h2>
|
|
||||||
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,67 +1,49 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import JoinMore from './JoinMore.svelte';
|
import { identityExists } from '$lib/stores';
|
||||||
import { identityStore } from '$lib/stores';
|
import DeleteIdentity from './identity/DeleteIdentity.svelte';
|
||||||
import { page } from '$app/stores';
|
import BackupIdentity from './identity/BackupIdentity.svelte';
|
||||||
import DeleteIdentity from './DeleteIdentity.svelte';
|
import RestoreIdentity from './identity/RestoreIdentity.svelte';
|
||||||
import BackupIdentity from './BackupIdentity.svelte';
|
|
||||||
import RestoreIdentity from './RestoreIdentity.svelte';
|
|
||||||
import { createIdentity } from '$lib/utils/';
|
import { createIdentity } from '$lib/utils/';
|
||||||
import { Tab, TabGroup } from '@skeletonlabs/skeleton';
|
import ActionRepresentation from './ui/ActionRepresentation.svelte';
|
||||||
import ActionRepresentation from './ActionRepresentation.svelte';
|
import IdentityIcon from 'svelte-material-icons/Account.svelte';
|
||||||
import { onMount } from 'svelte';
|
import Eye from 'svelte-material-icons/Eye.svelte';
|
||||||
$: identityExists = !!$identityStore._commitment;
|
|
||||||
let tabSet: number = 0;
|
|
||||||
onMount(() => {
|
|
||||||
if ($page.url.hash) {
|
|
||||||
const hash = $page.url.hash.replace('#', '');
|
|
||||||
if (hash === 'join-more') {
|
|
||||||
tabSet = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if !identityExists}
|
<h2 class="h2 mb-3 sm:mb-5 text-center">Manage Settings</h2>
|
||||||
<div class="mb-8 text-center">
|
{#if !$identityExists}
|
||||||
|
<div class="mb-3 sm:mb-8 text-center">
|
||||||
<span class="text-base italic px-4 py-2 font-mono badge variant-outline-error"
|
<span class="text-base italic px-4 py-2 font-mono badge variant-outline-error"
|
||||||
>Identity Not Found!</span
|
>Identity Not Found!</span
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="grid grid-flow-rows gap-5 my-5 max-w-md mx-auto">
|
<div class="flex flex-row flex-wrap gap-5 my-5 mx-auto justify-center">
|
||||||
{#if !identityExists}
|
{#if !$identityExists}
|
||||||
<button
|
<button
|
||||||
on:click={() => createIdentity()}
|
on:click={() => createIdentity()}
|
||||||
class="btn variant-ghost-primary font-medium"
|
class="btn variant-ghost-primary font-medium"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
Generate Identity
|
Generate New Identity
|
||||||
</button>
|
</button>
|
||||||
<RestoreIdentity />
|
<RestoreIdentity />
|
||||||
{:else}
|
{:else}
|
||||||
<TabGroup
|
<div>
|
||||||
justify="justify-around"
|
<h3 class="h3 flex flex-row gap-2 items-center"><IdentityIcon /> Identity</h3>
|
||||||
active="variant-soft-secondary"
|
<div class="flex flex-col gap-3 sm:gap-5 items-stretch">
|
||||||
flex="flex-1 lg:flex-none"
|
<BackupIdentity />
|
||||||
class="w-full"
|
<DeleteIdentity />
|
||||||
>
|
<RestoreIdentity />
|
||||||
<Tab bind:group={tabSet} name="id" value={0} class="center">
|
</div>
|
||||||
<span>Identity</span>
|
</div>
|
||||||
</Tab>
|
<div>
|
||||||
<Tab bind:group={tabSet} name="server" value={1}>Server</Tab>
|
<h3 class="h3 flex flex-row gap-2 items-center"><Eye /> UI</h3>
|
||||||
<Tab bind:group={tabSet} name="misc" value={2}>Settings</Tab>
|
<div class="flex flex-col gap-3 sm:gap-5 items-stretch">
|
||||||
<!-- Tab Panels --->
|
<ActionRepresentation />
|
||||||
<svelte:fragment slot="panel">
|
<BackupIdentity />
|
||||||
{#if tabSet === 0}
|
<DeleteIdentity />
|
||||||
<BackupIdentity />
|
<RestoreIdentity />
|
||||||
<DeleteIdentity />
|
</div>
|
||||||
<RestoreIdentity />
|
</div>
|
||||||
{:else if tabSet === 1}
|
|
||||||
<JoinMore />
|
|
||||||
{:else if tabSet === 2}
|
|
||||||
<ActionRepresentation />
|
|
||||||
{/if}
|
|
||||||
</svelte:fragment>
|
|
||||||
</TabGroup>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
9
src/routes/settings/identity/+page.svelte
Normal file
9
src/routes/settings/identity/+page.svelte
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<script>
|
||||||
|
import BackupIdentity from './BackupIdentity.svelte';
|
||||||
|
import DeleteIdentity from './DeleteIdentity.svelte';
|
||||||
|
import RestoreIdentity from './RestoreIdentity.svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<BackupIdentity />
|
||||||
|
<DeleteIdentity />
|
||||||
|
<RestoreIdentity />
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
import BackupIdentity from '$lib/components/BackupIdentity.svelte';
|
import BackupIdentity from '$lib/components/BackupIdentity.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="card variant-ghost-secondary mb-5">
|
<div class="card variant-ghost-secondary">
|
||||||
<header class="card-header">
|
<header class="card-header">
|
||||||
<h4 class="h4">Backup Your Identity</h4>
|
<h3 class="h4">Backup Your Identity</h3>
|
||||||
</header>
|
</header>
|
||||||
<section class="p-2 sm:p-4">
|
<section class="p-2 sm:p-4">
|
||||||
<BackupIdentity />
|
<BackupIdentity />
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="card variant-ghost-error mb-5">
|
<div class="card variant-ghost-error">
|
||||||
<header class="card-header">
|
<header class="card-header">
|
||||||
<h3 class="h4">Delete Your Identity & Reset Application</h3>
|
<h3 class="h4">Delete Your Identity & Reset Application</h3>
|
||||||
</header>
|
</header>
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
>I promise I backed up my identity, or I really want to destroy it forever.</span
|
>I promise I backed up my identity, or I really want to destroy it forever.</span
|
||||||
>
|
>
|
||||||
</section>
|
</section>
|
||||||
<footer class="card-footer text-center mb-2">
|
<footer class="card-footer text-center">
|
||||||
{#if !isButtonDisabled}
|
{#if !isButtonDisabled}
|
||||||
<button
|
<button
|
||||||
id="delete-identity"
|
id="delete-identity"
|
||||||
5
src/routes/settings/identity/backup/+page.svelte
Normal file
5
src/routes/settings/identity/backup/+page.svelte
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import BackupIdentity from '../BackupIdentity.svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<BackupIdentity />
|
||||||
5
src/routes/settings/identity/restore/+page.svelte
Normal file
5
src/routes/settings/identity/restore/+page.svelte
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import RestoreIdentity from '../RestoreIdentity.svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<RestoreIdentity />
|
||||||
47
src/routes/settings/security/+page.svelte
Normal file
47
src/routes/settings/security/+page.svelte
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { setPassword } from '$lib/utils';
|
||||||
|
import { passwordSet } from '$lib/stores';
|
||||||
|
|
||||||
|
const minPasswordLength = 4;
|
||||||
|
let r = '';
|
||||||
|
|
||||||
|
function onSubmit() {
|
||||||
|
if (r != '' && r != null && r != undefined && r.length >= minPasswordLength) {
|
||||||
|
setPassword(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="max-w-lg mx-auto">
|
||||||
|
{#if !$passwordSet}
|
||||||
|
<h2 class="h3 mb-3">Set A Password!</h2>
|
||||||
|
<p class="mt-3">
|
||||||
|
In order to secure your identity and other sensitive data that is stored in your browser, we
|
||||||
|
need you to set a password.
|
||||||
|
</p>
|
||||||
|
<p class="my-3">
|
||||||
|
This password is only used locally, there is not username and password for your account, so
|
||||||
|
don't forget to <a href="/settings/backup" title="Backup Identity">backup your identity</a>.
|
||||||
|
</p>
|
||||||
|
<form on:submit|preventDefault={() => onSubmit()} class="flex flex-col w-full">
|
||||||
|
<label for="setPasswordInput" class="label" />
|
||||||
|
<input
|
||||||
|
id="setPasswordInput"
|
||||||
|
type="password"
|
||||||
|
name="password"
|
||||||
|
class="input"
|
||||||
|
bind:value={r}
|
||||||
|
minlength={minPasswordLength}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<small>Minimum password length: {minPasswordLength}</small>
|
||||||
|
<button
|
||||||
|
class="btn variant-filled-primary mt-3"
|
||||||
|
disabled={r.length < minPasswordLength}
|
||||||
|
type="submit">Set Password</button
|
||||||
|
>
|
||||||
|
</form>
|
||||||
|
{:else}
|
||||||
|
<h2 class="h3">Password Set!</h2>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
39
src/routes/settings/status/+page.svelte
Normal file
39
src/routes/settings/status/+page.svelte
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { configStore, identityKeyStore, identityStore, serverStore } from '$lib/stores';
|
||||||
|
import { IdentityStoreE } from '$lib/types';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="status" class="flex flex-col gap-5">
|
||||||
|
<div>
|
||||||
|
<h2 class="h3">configStore</h2>
|
||||||
|
<div>Completed Signup: {JSON.stringify($configStore.signUpStatus.completedSignup)}</div>
|
||||||
|
<div>Identity Backedup: {JSON.stringify($configStore.signUpStatus.identityBackedUp)}</div>
|
||||||
|
<div>IdentityStore Type: {IdentityStoreE[$configStore.identityStore]}</div>
|
||||||
|
<div>Beta: {JSON.stringify($configStore.beta)}</div>
|
||||||
|
<div>Hashed Password: {JSON.stringify($configStore.hashedPwd)}</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2 class="h3">Identity Data</h2>
|
||||||
|
{#each Object.keys($identityStore) as key}
|
||||||
|
<div>Unprotected {key}: {JSON.stringify($identityStore[key])}</div>
|
||||||
|
{/each}
|
||||||
|
{#each Object.keys($identityKeyStore) as key}
|
||||||
|
<div>Protected {key}: {JSON.stringify($identityKeyStore[key])}</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2 class="h3">Server Data</h2>
|
||||||
|
{#each Object.keys($serverStore) as key}
|
||||||
|
<div>{$serverStore[key].name}:</div>
|
||||||
|
<div class="ps-5">id: {$serverStore[key].id}</div>
|
||||||
|
<div class="ps-5">version: {$serverStore[key].version}</div>
|
||||||
|
<div class="ps-5">url: {key}</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#status div div {
|
||||||
|
margin-left: 1.25rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
5
src/routes/settings/ui/+page.svelte
Normal file
5
src/routes/settings/ui/+page.svelte
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<script>
|
||||||
|
import ActionRepresentation from './ActionRepresentation.svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ActionRepresentation />
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
import AP from '$lib/components/AP.svelte';
|
import AP from '$lib/components/AP.svelte';
|
||||||
import { configStore } from '$lib/stores';
|
import { configStore } from '$lib/stores';
|
||||||
import { ActionRepresentationE } from '$lib/types';
|
import { ActionRepresentationE } from '$lib/types';
|
||||||
|
import { RangeSlider } from '@skeletonlabs/skeleton';
|
||||||
|
import { max } from 'date-fns';
|
||||||
$: if ($configStore.actionRepresentation == undefined) {
|
$: if ($configStore.actionRepresentation == undefined) {
|
||||||
$configStore.actionRepresentation = ActionRepresentationE.AP;
|
$configStore.actionRepresentation = ActionRepresentationE.AP;
|
||||||
}
|
}
|
||||||
@@ -12,7 +14,7 @@
|
|||||||
|
|
||||||
<div class="card variant-soft-secondary">
|
<div class="card variant-soft-secondary">
|
||||||
<header class="card-header">
|
<header class="card-header">
|
||||||
<h4 class="h4">Action Representation</h4>
|
<h3 class="h4">Action Representation</h3>
|
||||||
</header>
|
</header>
|
||||||
<section class="p-2 mb-2 sm:p-4 sm:mb-4">
|
<section class="p-2 mb-2 sm:p-4 sm:mb-4">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
@@ -31,14 +33,18 @@
|
|||||||
<div class="border-t mt-2 pt-2 mb-2 sm:mb-4 flex flex-col place-items-center">
|
<div class="border-t mt-2 pt-2 mb-2 sm:mb-4 flex flex-col place-items-center">
|
||||||
<h6 class="h6">Demo</h6>
|
<h6 class="h6">Demo</h6>
|
||||||
<AP {health} {maxHealth} />
|
<AP {health} {maxHealth} />
|
||||||
<label
|
<RangeSlider name="range-slider" bind:value={health} max={maxHealth} step={1} ticked>
|
||||||
><div>Health: {health}</div>
|
<div class="flex justify-between items-center">
|
||||||
<input type="range" min="0" max={maxHealth} bind:value={health} />
|
<div class="font-bold">Health</div>
|
||||||
</label>
|
<div class="text-xs">{health} / {maxHealth}</div>
|
||||||
<label
|
</div>
|
||||||
><div>Max Health: {maxHealth}</div>
|
</RangeSlider>
|
||||||
<input type="range" min="1" max={10} bind:value={maxHealth} />
|
<RangeSlider name="range-slider" bind:value={maxHealth} max={10} step={1} ticked>
|
||||||
</label>
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="font-bold">Max Health</div>
|
||||||
|
<div class="text-xs">{maxHealth} / {10}</div>
|
||||||
|
</div>
|
||||||
|
</RangeSlider>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -46,7 +46,6 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Console placeholder="/join invite-code-goes-here" />
|
|
||||||
<div>
|
<div>
|
||||||
<a href="/settings" class="btn btn-sm variant-ghost-primary">
|
<a href="/settings" class="btn btn-sm variant-ghost-primary">
|
||||||
<span>Restore Identity</span>
|
<span>Restore Identity</span>
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
# Installing Webfonts
|
# Installing Webfonts
|
||||||
|
|
||||||
Follow these simple Steps.
|
Follow these simple Steps.
|
||||||
|
|
||||||
## 1.
|
## 1.
|
||||||
|
|
||||||
Put `nippo/` Folder into a Folder called `fonts/`.
|
Put `nippo/` Folder into a Folder called `fonts/`.
|
||||||
|
|
||||||
## 2.
|
## 2.
|
||||||
|
|
||||||
Put `nippo.css` into your `css/` Folder.
|
Put `nippo.css` into your `css/` Folder.
|
||||||
|
|
||||||
## 3. (Optional)
|
## 3. (Optional)
|
||||||
|
|
||||||
You may adapt the `url('path')` in `nippo.css` depends on your Website Filesystem.
|
You may adapt the `url('path')` in `nippo.css` depends on your Website Filesystem.
|
||||||
|
|
||||||
## 4.
|
## 4.
|
||||||
|
|
||||||
Import `nippo.css` at the top of you main Stylesheet.
|
Import `nippo.css` at the top of you main Stylesheet.
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -19,7 +24,6 @@ Import `nippo.css` at the top of you main Stylesheet.
|
|||||||
|
|
||||||
## 5.
|
## 5.
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
font-family: 'Nippo-Variable';
|
font-family: 'Nippo-Variable';
|
||||||
font-family: 'Nippo-Extralight';
|
font-family: 'Nippo-Extralight';
|
||||||
@@ -28,4 +32,3 @@ font-family: 'Nippo-Regular';
|
|||||||
font-family: 'Nippo-Medium';
|
font-family: 'Nippo-Medium';
|
||||||
font-family: 'Nippo-Bold';
|
font-family: 'Nippo-Bold';
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a variable font
|
* This is a variable font
|
||||||
* You can controll variable axes as shown below:
|
* You can controll variable axes as shown below:
|
||||||
@@ -29,67 +28,61 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Nippo-Variable';
|
font-family: 'Nippo-Variable';
|
||||||
src: url('../fonts/Nippo-Variable.woff2') format('woff2'),
|
src: url('../fonts/Nippo-Variable.woff2') format('woff2'),
|
||||||
url('../fonts/Nippo-Variable.woff') format('woff'),
|
url('../fonts/Nippo-Variable.woff') format('woff'),
|
||||||
url('../fonts/Nippo-Variable.ttf') format('truetype');
|
url('../fonts/Nippo-Variable.ttf') format('truetype');
|
||||||
font-weight: 200 700;
|
font-weight: 200 700;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Nippo-Extralight';
|
font-family: 'Nippo-Extralight';
|
||||||
src: url('../fonts/Nippo-Extralight.woff2') format('woff2'),
|
src: url('../fonts/Nippo-Extralight.woff2') format('woff2'),
|
||||||
url('../fonts/Nippo-Extralight.woff') format('woff'),
|
url('../fonts/Nippo-Extralight.woff') format('woff'),
|
||||||
url('../fonts/Nippo-Extralight.ttf') format('truetype');
|
url('../fonts/Nippo-Extralight.ttf') format('truetype');
|
||||||
font-weight: 200;
|
font-weight: 200;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Nippo-Light';
|
font-family: 'Nippo-Light';
|
||||||
src: url('../fonts/Nippo-Light.woff2') format('woff2'),
|
src: url('../fonts/Nippo-Light.woff2') format('woff2'),
|
||||||
url('../fonts/Nippo-Light.woff') format('woff'),
|
url('../fonts/Nippo-Light.woff') format('woff'),
|
||||||
url('../fonts/Nippo-Light.ttf') format('truetype');
|
url('../fonts/Nippo-Light.ttf') format('truetype');
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Nippo-Regular';
|
font-family: 'Nippo-Regular';
|
||||||
src: url('../fonts/Nippo-Regular.woff2') format('woff2'),
|
src: url('../fonts/Nippo-Regular.woff2') format('woff2'),
|
||||||
url('../fonts/Nippo-Regular.woff') format('woff'),
|
url('../fonts/Nippo-Regular.woff') format('woff'),
|
||||||
url('../fonts/Nippo-Regular.ttf') format('truetype');
|
url('../fonts/Nippo-Regular.ttf') format('truetype');
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Nippo-Medium';
|
font-family: 'Nippo-Medium';
|
||||||
src: url('../fonts/Nippo-Medium.woff2') format('woff2'),
|
src: url('../fonts/Nippo-Medium.woff2') format('woff2'),
|
||||||
url('../fonts/Nippo-Medium.woff') format('woff'),
|
url('../fonts/Nippo-Medium.woff') format('woff'),
|
||||||
url('../fonts/Nippo-Medium.ttf') format('truetype');
|
url('../fonts/Nippo-Medium.ttf') format('truetype');
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Nippo-Bold';
|
font-family: 'Nippo-Bold';
|
||||||
src: url('../fonts/Nippo-Bold.woff2') format('woff2'),
|
src: url('../fonts/Nippo-Bold.woff2') format('woff2'),
|
||||||
url('../fonts/Nippo-Bold.woff') format('woff'),
|
url('../fonts/Nippo-Bold.woff') format('woff'),
|
||||||
url('../fonts/Nippo-Bold.ttf') format('truetype');
|
url('../fonts/Nippo-Bold.ttf') format('truetype');
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
{
|
{
|
||||||
"name": "App",
|
"name": "App",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "\/android-icon-36x36.png",
|
"src": "/android-icon-36x36.png",
|
||||||
"sizes": "36x36",
|
"sizes": "36x36",
|
||||||
"type": "image\/png",
|
"type": "image/png",
|
||||||
"density": "0.75"
|
"density": "0.75"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "\/android-icon-48x48.png",
|
"src": "/android-icon-48x48.png",
|
||||||
"sizes": "48x48",
|
"sizes": "48x48",
|
||||||
"type": "image\/png",
|
"type": "image/png",
|
||||||
"density": "1.0"
|
"density": "1.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "\/android-icon-72x72.png",
|
"src": "/android-icon-72x72.png",
|
||||||
"sizes": "72x72",
|
"sizes": "72x72",
|
||||||
"type": "image\/png",
|
"type": "image/png",
|
||||||
"density": "1.5"
|
"density": "1.5"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "\/android-icon-96x96.png",
|
"src": "/android-icon-96x96.png",
|
||||||
"sizes": "96x96",
|
"sizes": "96x96",
|
||||||
"type": "image\/png",
|
"type": "image/png",
|
||||||
"density": "2.0"
|
"density": "2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "\/android-icon-144x144.png",
|
"src": "/android-icon-144x144.png",
|
||||||
"sizes": "144x144",
|
"sizes": "144x144",
|
||||||
"type": "image\/png",
|
"type": "image/png",
|
||||||
"density": "3.0"
|
"density": "3.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "\/android-icon-192x192.png",
|
"src": "/android-icon-192x192.png",
|
||||||
"sizes": "192x192",
|
"sizes": "192x192",
|
||||||
"type": "image\/png",
|
"type": "image/png",
|
||||||
"density": "4.0"
|
"density": "4.0"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,114 +1,105 @@
|
|||||||
{
|
{
|
||||||
"protocol": "groth16",
|
"protocol": "groth16",
|
||||||
"curve": "bn128",
|
"curve": "bn128",
|
||||||
"nPublic": 5,
|
"nPublic": 5,
|
||||||
"vk_alpha_1": [
|
"vk_alpha_1": [
|
||||||
"20491192805390485299153009773594534940189261866228447918068658471970481763042",
|
"20491192805390485299153009773594534940189261866228447918068658471970481763042",
|
||||||
"9383485363053290200918347156157836566562967994039712273449902621266178545958",
|
"9383485363053290200918347156157836566562967994039712273449902621266178545958",
|
||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"vk_beta_2": [
|
"vk_beta_2": [
|
||||||
[
|
[
|
||||||
"6375614351688725206403948262868962793625744043794305715222011528459656738731",
|
"6375614351688725206403948262868962793625744043794305715222011528459656738731",
|
||||||
"4252822878758300859123897981450591353533073413197771768651442665752259397132"
|
"4252822878758300859123897981450591353533073413197771768651442665752259397132"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"10505242626370262277552901082094356697409835680220590971873171140371331206856",
|
"10505242626370262277552901082094356697409835680220590971873171140371331206856",
|
||||||
"21847035105528745403288232691147584728191162732299865338377159692350059136679"
|
"21847035105528745403288232691147584728191162732299865338377159692350059136679"
|
||||||
],
|
],
|
||||||
[
|
["1", "0"]
|
||||||
"1",
|
],
|
||||||
"0"
|
"vk_gamma_2": [
|
||||||
]
|
[
|
||||||
],
|
"10857046999023057135944570762232829481370756359578518086990519993285655852781",
|
||||||
"vk_gamma_2": [
|
"11559732032986387107991004021392285783925812861821192530917403151452391805634"
|
||||||
[
|
],
|
||||||
"10857046999023057135944570762232829481370756359578518086990519993285655852781",
|
[
|
||||||
"11559732032986387107991004021392285783925812861821192530917403151452391805634"
|
"8495653923123431417604973247489272438418190587263600148770280649306958101930",
|
||||||
],
|
"4082367875863433681332203403145435568316851327593401208105741076214120093531"
|
||||||
[
|
],
|
||||||
"8495653923123431417604973247489272438418190587263600148770280649306958101930",
|
["1", "0"]
|
||||||
"4082367875863433681332203403145435568316851327593401208105741076214120093531"
|
],
|
||||||
],
|
"vk_delta_2": [
|
||||||
[
|
[
|
||||||
"1",
|
"3817638527075299341910923013750491829772293424386698324526317429044327254930",
|
||||||
"0"
|
"16817041674734304676071688134655235316477394149172545683919861305510126014325"
|
||||||
]
|
],
|
||||||
],
|
[
|
||||||
"vk_delta_2": [
|
"15321616806892601534034512759307826486280009165298528953245727688557811743473",
|
||||||
[
|
"6325777744419158965546141708181579937852352378408429766464847802592525079966"
|
||||||
"3817638527075299341910923013750491829772293424386698324526317429044327254930",
|
],
|
||||||
"16817041674734304676071688134655235316477394149172545683919861305510126014325"
|
["1", "0"]
|
||||||
],
|
],
|
||||||
[
|
"vk_alphabeta_12": [
|
||||||
"15321616806892601534034512759307826486280009165298528953245727688557811743473",
|
[
|
||||||
"6325777744419158965546141708181579937852352378408429766464847802592525079966"
|
[
|
||||||
],
|
"2029413683389138792403550203267699914886160938906632433982220835551125967885",
|
||||||
[
|
"21072700047562757817161031222997517981543347628379360635925549008442030252106"
|
||||||
"1",
|
],
|
||||||
"0"
|
[
|
||||||
]
|
"5940354580057074848093997050200682056184807770593307860589430076672439820312",
|
||||||
],
|
"12156638873931618554171829126792193045421052652279363021382169897324752428276"
|
||||||
"vk_alphabeta_12": [
|
],
|
||||||
[
|
[
|
||||||
[
|
"7898200236362823042373859371574133993780991612861777490112507062703164551277",
|
||||||
"2029413683389138792403550203267699914886160938906632433982220835551125967885",
|
"7074218545237549455313236346927434013100842096812539264420499035217050630853"
|
||||||
"21072700047562757817161031222997517981543347628379360635925549008442030252106"
|
]
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"5940354580057074848093997050200682056184807770593307860589430076672439820312",
|
[
|
||||||
"12156638873931618554171829126792193045421052652279363021382169897324752428276"
|
"7077479683546002997211712695946002074877511277312570035766170199895071832130",
|
||||||
],
|
"10093483419865920389913245021038182291233451549023025229112148274109565435465"
|
||||||
[
|
],
|
||||||
"7898200236362823042373859371574133993780991612861777490112507062703164551277",
|
[
|
||||||
"7074218545237549455313236346927434013100842096812539264420499035217050630853"
|
"4595479056700221319381530156280926371456704509942304414423590385166031118820",
|
||||||
]
|
"19831328484489333784475432780421641293929726139240675179672856274388269393268"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
[
|
"11934129596455521040620786944827826205713621633706285934057045369193958244500",
|
||||||
"7077479683546002997211712695946002074877511277312570035766170199895071832130",
|
"8037395052364110730298837004334506829870972346962140206007064471173334027475"
|
||||||
"10093483419865920389913245021038182291233451549023025229112148274109565435465"
|
]
|
||||||
],
|
]
|
||||||
[
|
],
|
||||||
"4595479056700221319381530156280926371456704509942304414423590385166031118820",
|
"IC": [
|
||||||
"19831328484489333784475432780421641293929726139240675179672856274388269393268"
|
[
|
||||||
],
|
"4920513730204767532050733107749276406754520419375654722016092399980613788208",
|
||||||
[
|
"10950491564509418434657706642388934308456795265036074733953533582377584967294",
|
||||||
"11934129596455521040620786944827826205713621633706285934057045369193958244500",
|
"1"
|
||||||
"8037395052364110730298837004334506829870972346962140206007064471173334027475"
|
],
|
||||||
]
|
[
|
||||||
]
|
"6815064660695497986531118446154820702646540722664044216580897159556261271171",
|
||||||
],
|
"17838140936832571103329556013529166877877534025488014783346458943575275015438",
|
||||||
"IC": [
|
"1"
|
||||||
[
|
],
|
||||||
"4920513730204767532050733107749276406754520419375654722016092399980613788208",
|
[
|
||||||
"10950491564509418434657706642388934308456795265036074733953533582377584967294",
|
"16364982450206976302246609763791333525052810246590359380676749324389440643932",
|
||||||
"1"
|
"17092624338100676284548565502349491320314889021833923882585524649862570629227",
|
||||||
],
|
"1"
|
||||||
[
|
],
|
||||||
"6815064660695497986531118446154820702646540722664044216580897159556261271171",
|
[
|
||||||
"17838140936832571103329556013529166877877534025488014783346458943575275015438",
|
"3679639231485547795420532910726924727560917141402837495597760107842698404034",
|
||||||
"1"
|
"16213191511474848247596810551723578773353083440353745908057321946068926848382",
|
||||||
],
|
"1"
|
||||||
[
|
],
|
||||||
"16364982450206976302246609763791333525052810246590359380676749324389440643932",
|
[
|
||||||
"17092624338100676284548565502349491320314889021833923882585524649862570629227",
|
"9215428431027260354679105025212521481930206886203677270216204485256690813172",
|
||||||
"1"
|
"934602510541226149881779979217731465262250233587980565969044391353665291792",
|
||||||
],
|
"1"
|
||||||
[
|
],
|
||||||
"3679639231485547795420532910726924727560917141402837495597760107842698404034",
|
[
|
||||||
"16213191511474848247596810551723578773353083440353745908057321946068926848382",
|
"8935861545794299876685457331391349387048184820319250771243971382360441890897",
|
||||||
"1"
|
"4993459033694759724715904486381952906869986989682015547152342336961693234616",
|
||||||
],
|
"1"
|
||||||
[
|
]
|
||||||
"9215428431027260354679105025212521481930206886203677270216204485256690813172",
|
]
|
||||||
"934602510541226149881779979217731465262250233587980565969044391353665291792",
|
}
|
||||||
"1"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"8935861545794299876685457331391349387048184820319250771243971382360441890897",
|
|
||||||
"4993459033694759724715904486381952906869986989682015547152342336961693234616",
|
|
||||||
"1"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,99 +1,90 @@
|
|||||||
{
|
{
|
||||||
"protocol": "groth16",
|
"protocol": "groth16",
|
||||||
"curve": "bn128",
|
"curve": "bn128",
|
||||||
"nPublic": 2,
|
"nPublic": 2,
|
||||||
"vk_alpha_1": [
|
"vk_alpha_1": [
|
||||||
"20491192805390485299153009773594534940189261866228447918068658471970481763042",
|
"20491192805390485299153009773594534940189261866228447918068658471970481763042",
|
||||||
"9383485363053290200918347156157836566562967994039712273449902621266178545958",
|
"9383485363053290200918347156157836566562967994039712273449902621266178545958",
|
||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"vk_beta_2": [
|
"vk_beta_2": [
|
||||||
[
|
[
|
||||||
"6375614351688725206403948262868962793625744043794305715222011528459656738731",
|
"6375614351688725206403948262868962793625744043794305715222011528459656738731",
|
||||||
"4252822878758300859123897981450591353533073413197771768651442665752259397132"
|
"4252822878758300859123897981450591353533073413197771768651442665752259397132"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"10505242626370262277552901082094356697409835680220590971873171140371331206856",
|
"10505242626370262277552901082094356697409835680220590971873171140371331206856",
|
||||||
"21847035105528745403288232691147584728191162732299865338377159692350059136679"
|
"21847035105528745403288232691147584728191162732299865338377159692350059136679"
|
||||||
],
|
],
|
||||||
[
|
["1", "0"]
|
||||||
"1",
|
],
|
||||||
"0"
|
"vk_gamma_2": [
|
||||||
]
|
[
|
||||||
],
|
"10857046999023057135944570762232829481370756359578518086990519993285655852781",
|
||||||
"vk_gamma_2": [
|
"11559732032986387107991004021392285783925812861821192530917403151452391805634"
|
||||||
[
|
],
|
||||||
"10857046999023057135944570762232829481370756359578518086990519993285655852781",
|
[
|
||||||
"11559732032986387107991004021392285783925812861821192530917403151452391805634"
|
"8495653923123431417604973247489272438418190587263600148770280649306958101930",
|
||||||
],
|
"4082367875863433681332203403145435568316851327593401208105741076214120093531"
|
||||||
[
|
],
|
||||||
"8495653923123431417604973247489272438418190587263600148770280649306958101930",
|
["1", "0"]
|
||||||
"4082367875863433681332203403145435568316851327593401208105741076214120093531"
|
],
|
||||||
],
|
"vk_delta_2": [
|
||||||
[
|
[
|
||||||
"1",
|
"11983007890138271431646631339128325393343025477496193427884097571341594637227",
|
||||||
"0"
|
"7369399572723042520302573420729576910581887995143697476970345965043452827346"
|
||||||
]
|
],
|
||||||
],
|
[
|
||||||
"vk_delta_2": [
|
"18498623948725074905368922260006856461276039836160071250761949723295691187028",
|
||||||
[
|
"20253812994897318378765322974844822348210001364477588185294466023467389614920"
|
||||||
"11983007890138271431646631339128325393343025477496193427884097571341594637227",
|
],
|
||||||
"7369399572723042520302573420729576910581887995143697476970345965043452827346"
|
["1", "0"]
|
||||||
],
|
],
|
||||||
[
|
"vk_alphabeta_12": [
|
||||||
"18498623948725074905368922260006856461276039836160071250761949723295691187028",
|
[
|
||||||
"20253812994897318378765322974844822348210001364477588185294466023467389614920"
|
[
|
||||||
],
|
"2029413683389138792403550203267699914886160938906632433982220835551125967885",
|
||||||
[
|
"21072700047562757817161031222997517981543347628379360635925549008442030252106"
|
||||||
"1",
|
],
|
||||||
"0"
|
[
|
||||||
]
|
"5940354580057074848093997050200682056184807770593307860589430076672439820312",
|
||||||
],
|
"12156638873931618554171829126792193045421052652279363021382169897324752428276"
|
||||||
"vk_alphabeta_12": [
|
],
|
||||||
[
|
[
|
||||||
[
|
"7898200236362823042373859371574133993780991612861777490112507062703164551277",
|
||||||
"2029413683389138792403550203267699914886160938906632433982220835551125967885",
|
"7074218545237549455313236346927434013100842096812539264420499035217050630853"
|
||||||
"21072700047562757817161031222997517981543347628379360635925549008442030252106"
|
]
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"5940354580057074848093997050200682056184807770593307860589430076672439820312",
|
[
|
||||||
"12156638873931618554171829126792193045421052652279363021382169897324752428276"
|
"7077479683546002997211712695946002074877511277312570035766170199895071832130",
|
||||||
],
|
"10093483419865920389913245021038182291233451549023025229112148274109565435465"
|
||||||
[
|
],
|
||||||
"7898200236362823042373859371574133993780991612861777490112507062703164551277",
|
[
|
||||||
"7074218545237549455313236346927434013100842096812539264420499035217050630853"
|
"4595479056700221319381530156280926371456704509942304414423590385166031118820",
|
||||||
]
|
"19831328484489333784475432780421641293929726139240675179672856274388269393268"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
[
|
"11934129596455521040620786944827826205713621633706285934057045369193958244500",
|
||||||
"7077479683546002997211712695946002074877511277312570035766170199895071832130",
|
"8037395052364110730298837004334506829870972346962140206007064471173334027475"
|
||||||
"10093483419865920389913245021038182291233451549023025229112148274109565435465"
|
]
|
||||||
],
|
]
|
||||||
[
|
],
|
||||||
"4595479056700221319381530156280926371456704509942304414423590385166031118820",
|
"IC": [
|
||||||
"19831328484489333784475432780421641293929726139240675179672856274388269393268"
|
[
|
||||||
],
|
"19490069286251317200471893224761952280235157078692599655063040494106083015102",
|
||||||
[
|
"15613730057977833735664106983317680013118142165231654768046521650638333652991",
|
||||||
"11934129596455521040620786944827826205713621633706285934057045369193958244500",
|
"1"
|
||||||
"8037395052364110730298837004334506829870972346962140206007064471173334027475"
|
],
|
||||||
]
|
[
|
||||||
]
|
"1563543155852853229359605494188815884199915022658219002707722789976065966419",
|
||||||
],
|
"858819375930654753672617171465307097688802650498051619587167586479724200799",
|
||||||
"IC": [
|
"1"
|
||||||
[
|
],
|
||||||
"19490069286251317200471893224761952280235157078692599655063040494106083015102",
|
[
|
||||||
"15613730057977833735664106983317680013118142165231654768046521650638333652991",
|
"3808889614445935800597561392085733302718838702771107544944545050886958022904",
|
||||||
"1"
|
"13293649293049947010793838294353767499934999769633605908974566715226392122400",
|
||||||
],
|
"1"
|
||||||
[
|
]
|
||||||
"1563543155852853229359605494188815884199915022658219002707722789976065966419",
|
]
|
||||||
"858819375930654753672617171465307097688802650498051619587167586479724200799",
|
}
|
||||||
"1"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"3808889614445935800597561392085733302718838702771107544944545050886958022904",
|
|
||||||
"13293649293049947010793838294353767499934999769633605908974566715226392122400",
|
|
||||||
"1"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,17 +4,10 @@ import { vitePreprocess } from '@sveltejs/kit/vite';
|
|||||||
|
|
||||||
/** @type {import('@sveltejs/kit').Config} */
|
/** @type {import('@sveltejs/kit').Config} */
|
||||||
const config = {
|
const config = {
|
||||||
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
|
|
||||||
// for more information about preprocessors
|
|
||||||
preprocess: [vitePreprocess({})],
|
|
||||||
|
|
||||||
|
preprocess: [vitePreprocess({})],
|
||||||
kit: {
|
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({
|
adapter: adapter({
|
||||||
// default options are shown. On some platforms
|
|
||||||
// these options are set automatically — see below
|
|
||||||
pages: 'build',
|
pages: 'build',
|
||||||
assets: 'build',
|
assets: 'build',
|
||||||
fallback: 'index.html',
|
fallback: 'index.html',
|
||||||
@@ -25,5 +18,3 @@ const config = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import type { Config } from 'tailwindcss';
|
import type { Config } from 'tailwindcss';
|
||||||
import { discreetlyTheme } from './theme';
|
|
||||||
import { skeleton } from '@skeletonlabs/tw-plugin';
|
|
||||||
import forms from '@tailwindcss/forms';
|
import forms from '@tailwindcss/forms';
|
||||||
|
import typography from '@tailwindcss/typography';
|
||||||
|
import { skeleton } from '@skeletonlabs/tw-plugin';
|
||||||
|
import { discreetlyTheme } from './theme';
|
||||||
|
|
||||||
const config = {
|
export default {
|
||||||
darkMode: 'class',
|
darkMode: 'class',
|
||||||
content: [
|
content: [
|
||||||
'./src/**/*.{html,js,svelte,ts}',
|
'./src/**/*.{html,js,svelte,ts}',
|
||||||
@@ -14,11 +15,11 @@ const config = {
|
|||||||
extend: {}
|
extend: {}
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
forms,
|
||||||
|
typography,
|
||||||
skeleton({
|
skeleton({
|
||||||
themes: { custom: [discreetlyTheme] }
|
themes: { custom: [discreetlyTheme] }
|
||||||
}),
|
}),
|
||||||
forms
|
forms
|
||||||
]
|
]
|
||||||
} satisfies Config;
|
} satisfies Config;
|
||||||
|
|
||||||
export default config;
|
|
||||||
|
|||||||
28
tests/app.test.ts
Normal file
28
tests/app.test.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { expect, test } from '@playwright/test';
|
||||||
|
import { getLocalStorage } from './utils';
|
||||||
|
|
||||||
|
test.describe('/', () => {
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
await page.goto('/');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('mount', async ({ page }) => {
|
||||||
|
await expect(page.getByRole('heading', { name: 'Welcome to Discreetly' })).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('default servers should be set', async ({ page }) => {
|
||||||
|
const localStorage = await getLocalStorage(page);
|
||||||
|
localStorage.forEach((object) => {
|
||||||
|
switch (object.name) {
|
||||||
|
case 'selectedServer':
|
||||||
|
expect(object.value).toBe('"https://server.discreetly.chat/"');
|
||||||
|
break;
|
||||||
|
case 'serverData':
|
||||||
|
expect(object.value).toBe(
|
||||||
|
'{"https://server.discreetly.chat/":{"name":"Discreetly Server","url":"https://server.discreetly.chat/"}}'
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
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();
|
|
||||||
});
|
|
||||||
6
tests/utils.ts
Normal file
6
tests/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import type { Page } from '@playwright/test';
|
||||||
|
|
||||||
|
export async function getLocalStorage(page: Page) {
|
||||||
|
const state = await page.context().storageState();
|
||||||
|
return state.origins[0].localStorage;
|
||||||
|
}
|
||||||
@@ -1,17 +1,10 @@
|
|||||||
|
import { purgeCss } from 'vite-plugin-tailwind-purgecss';
|
||||||
import { sveltekit } from '@sveltejs/kit/vite';
|
import { sveltekit } from '@sveltejs/kit/vite';
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vitest/config';
|
||||||
import sizes from 'rollup-plugin-sizes';
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [sveltekit()],
|
plugins: [sveltekit(), purgeCss()],
|
||||||
build: {
|
test: {
|
||||||
minify: 'terser',
|
include: ['src/**/*.{test,spec}.{js,ts}']
|
||||||
cssMinify: 'lightningcss',
|
|
||||||
rollupOptions: {
|
|
||||||
plugins: [sizes()],
|
|
||||||
output: {
|
|
||||||
compact: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user