mirror of
https://github.com/Discreetly/frontend.git
synced 2026-01-09 12:58:03 -05:00
EnterRoomPassword
This commit is contained in:
@@ -158,3 +158,55 @@ export async function createInvite(
|
||||
export async function getAllRooms(serverUrl: string, username: string, password: string) {
|
||||
return getAuth([serverUrl, `admin/rooms`], username, password) as Promise<RoomI[]>;
|
||||
}
|
||||
|
||||
interface CheckResponse {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
// include other properties as needed
|
||||
}
|
||||
|
||||
export async function postCheckRoomPassword(
|
||||
serverUrl: string,
|
||||
roomId: string,
|
||||
passwordHash: string
|
||||
): Promise<boolean> {
|
||||
const response = (await post([serverUrl, `room/checkpasswordhash/${roomId}`], {
|
||||
passwordHash
|
||||
})) as CheckResponse;
|
||||
return Boolean(response.success);
|
||||
}
|
||||
|
||||
export async function postSetRoomPassword(
|
||||
serverUrl: string,
|
||||
roomId: string,
|
||||
passwordHash: string
|
||||
): Promise<boolean> {
|
||||
const prover = new Prover('idcNullifier/circuit.wasm', 'idcNullifier/final.zkey');
|
||||
const id = getIdentity() as IdentityData;
|
||||
const idForProof: Partial<IdentityData> = {};
|
||||
if (id) {
|
||||
const timestamp = BigInt(Date.now());
|
||||
idForProof.trapdoor = id._trapdoor;
|
||||
idForProof.nullifier = id._nullifier;
|
||||
idForProof.secret = id._secret;
|
||||
idForProof.commitment = id._commitment;
|
||||
|
||||
// Proves you know the identity secret with a timestamp so this proof can't be replayed
|
||||
prover
|
||||
.generateProof({
|
||||
identity: idForProof as unknown as Identity,
|
||||
externalNullifier: timestamp
|
||||
})
|
||||
.then(async (proof) => {
|
||||
const response = (await post([serverUrl, `room/setpassword/${roomId}`], {
|
||||
passwordHash,
|
||||
proof
|
||||
})) as CheckResponse;
|
||||
return response.success;
|
||||
});
|
||||
} else {
|
||||
alertQueue.enqueue('No identity found when fetching rooms', 'error');
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -96,10 +96,36 @@ export const saltStore = storable('', 'salt');
|
||||
* !WARN NEVER CHANGE THE STORE TYPE OR YOU RISK EXPOSING THE KEY
|
||||
*/
|
||||
export const keyStore = writable({} as keyStoreI);
|
||||
|
||||
/**
|
||||
* @description This is the in memory cryptokeys derived from the
|
||||
* room specific passwords stored in roomPassStore, which is encrypted in local storage
|
||||
* so keyStore is used to decrypt roomPassStore, which is used to decrypt each rooms
|
||||
* roomKeyStore, which is then used to decrypt messages in each corresponding room
|
||||
*/
|
||||
export const roomKeyStore = writable({} as roomKeyStoreI);
|
||||
|
||||
export const alertQueue = queueable([]);
|
||||
|
||||
export const roomPasswordSet = derived(
|
||||
[currentSelectedRoom, roomPassStore],
|
||||
([$currentSelectedRoom, $roomPassStore]) => {
|
||||
if ($currentSelectedRoom.encrypted == 'AES') {
|
||||
if ($roomPassStore[$currentSelectedRoom.roomId.toString()]) {
|
||||
if ($roomPassStore[$currentSelectedRoom.roomId.toString()].length > 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* @description Configuration store, stores the user's settings
|
||||
*/
|
||||
|
||||
@@ -55,10 +55,15 @@ export interface consoleStoreI {
|
||||
};
|
||||
}
|
||||
|
||||
// keyed by the roomId, encrypted in localstorage
|
||||
export interface roomPassStoreI {
|
||||
[key: string]: string;
|
||||
[key: string]: {
|
||||
password: string;
|
||||
hashedSaltedPassword: string;
|
||||
};
|
||||
}
|
||||
|
||||
// keyed by the roomId, only in memory
|
||||
export interface roomKeyStoreI {
|
||||
[key: string]: CryptoKey;
|
||||
}
|
||||
|
||||
@@ -7,11 +7,13 @@ import {
|
||||
keyStore,
|
||||
identityExists,
|
||||
alertQueue,
|
||||
roomPassStore
|
||||
roomPassStore,
|
||||
selectedServer
|
||||
} from '$lib/stores';
|
||||
import { encryptIdentity } from './identity';
|
||||
import type { IdentityStoreI } from '$lib/types';
|
||||
import { updateRooms } from '.';
|
||||
import { postCheckRoomPassword, postSetRoomPassword } from '$lib/services/server';
|
||||
|
||||
export async function setPassword(password: string): Promise<'success' | string> {
|
||||
const hashedPassword = await hashPassword(password);
|
||||
@@ -79,3 +81,39 @@ export async function unlockPadlock(password: string) {
|
||||
keyStore.set(null);
|
||||
}
|
||||
}
|
||||
|
||||
export async function enterRoomPassword(password: string, roomId: string): Promise<boolean> {
|
||||
const hashedSaltedPassword = await hashPassword(password + roomId);
|
||||
if (hashedSaltedPassword) {
|
||||
postCheckRoomPassword(get(selectedServer), roomId, hashedSaltedPassword).then((res) => {
|
||||
if (res) {
|
||||
roomPassStore.update((roomPass) => {
|
||||
roomPass[roomId] = { password, hashedSaltedPassword };
|
||||
return roomPass;
|
||||
});
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function setRoomPassword(password: string, roomId: string): Promise<boolean> {
|
||||
const hashedSaltedPassword = await hashPassword(password + roomId);
|
||||
if (hashedSaltedPassword) {
|
||||
postSetRoomPassword(get(selectedServer), roomId, hashedSaltedPassword).then((res) => {
|
||||
if (res) {
|
||||
roomPassStore.update((roomPass) => {
|
||||
roomPass[roomId] = { password, hashedSaltedPassword };
|
||||
return roomPass;
|
||||
});
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ function updateRoomStore(rooms: RoomI[], serverURL: string = get(selectedServer)
|
||||
}
|
||||
newStore[roomId] = { ...room, server: serverURL };
|
||||
});
|
||||
console.debug(newStore);
|
||||
return newStore;
|
||||
});
|
||||
// Update the serverStore
|
||||
@@ -142,8 +141,6 @@ export function addMessageToRoom(roomId: string, data: MessageI) {
|
||||
}
|
||||
|
||||
// Add the new message
|
||||
const test = [...currentStore[roomId]];
|
||||
|
||||
currentStore[roomId] = [...currentStore[roomId], data];
|
||||
|
||||
// Trim messages to the last 500
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
selectedServer,
|
||||
configStore,
|
||||
currentRoomsStore,
|
||||
numberServers
|
||||
roomPasswordSet
|
||||
} from '$lib/stores';
|
||||
import RoomPassword from './RoomPassword.svelte';
|
||||
import { Experiences } from '$lib/types';
|
||||
import { addMessageToRoom, getTimestampFromEpoch, updateMessages, updateRooms } from '$lib/utils';
|
||||
import { getToastStore } from '@skeletonlabs/skeleton';
|
||||
@@ -150,43 +151,47 @@
|
||||
</script>
|
||||
|
||||
{#if $currentSelectedRoom}
|
||||
<div
|
||||
id="chat"
|
||||
class="grid grid-rows-[auto,1fr,auto]">
|
||||
<ChatRoomHeader
|
||||
{connected}
|
||||
{currentEpoch}
|
||||
{timeLeftInEpoch}
|
||||
{userMessageLimit}
|
||||
{roomRateLimit}
|
||||
{onlineMembers} />
|
||||
{#if $configStore.experience == Experiences.Chat}
|
||||
{#key $currentSelectedRoom.roomId}
|
||||
<Conversation {roomRateLimit} />
|
||||
{/key}
|
||||
<InputPrompt
|
||||
{socket}
|
||||
{#if $roomPasswordSet}
|
||||
<div
|
||||
id="chat"
|
||||
class="grid grid-rows-[auto,1fr,auto]">
|
||||
<ChatRoomHeader
|
||||
{connected}
|
||||
{currentEpoch}
|
||||
{timeLeftInEpoch}
|
||||
{userMessageLimit}
|
||||
{roomId} />
|
||||
{:else if $configStore.experience == Experiences.Draw}
|
||||
<Draw />
|
||||
{:else}
|
||||
{#key $currentSelectedRoom.roomId}
|
||||
<Conversation {roomRateLimit} />
|
||||
{/key}
|
||||
<InputPrompt
|
||||
{socket}
|
||||
{connected}
|
||||
{currentEpoch}
|
||||
{userMessageLimit}
|
||||
{roomId} />
|
||||
{/if}
|
||||
<!-- Conversation -->
|
||||
{roomRateLimit}
|
||||
{onlineMembers} />
|
||||
{#if $configStore.experience == Experiences.Chat}
|
||||
{#key $currentSelectedRoom.roomId}
|
||||
<Conversation {roomRateLimit} />
|
||||
{/key}
|
||||
<InputPrompt
|
||||
{socket}
|
||||
{connected}
|
||||
{currentEpoch}
|
||||
{userMessageLimit}
|
||||
{roomId} />
|
||||
{:else if $configStore.experience == Experiences.Draw}
|
||||
<Draw />
|
||||
{:else}
|
||||
{#key $currentSelectedRoom.roomId}
|
||||
<Conversation {roomRateLimit} />
|
||||
{/key}
|
||||
<InputPrompt
|
||||
{socket}
|
||||
{connected}
|
||||
{currentEpoch}
|
||||
{userMessageLimit}
|
||||
{roomId} />
|
||||
{/if}
|
||||
<!-- Conversation -->
|
||||
|
||||
<!-- Prompt -->
|
||||
</div>
|
||||
<!-- Prompt -->
|
||||
</div>
|
||||
{:else}
|
||||
<div><RoomPassword {roomId} /></div>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="grid place-content-center">
|
||||
<h6 class="h2 text-center mb-10">You aren't in any rooms...yet</h6>
|
||||
|
||||
35
src/routes/chat/RoomPassword.svelte
Normal file
35
src/routes/chat/RoomPassword.svelte
Normal file
@@ -0,0 +1,35 @@
|
||||
<script lang="ts">
|
||||
import { enterRoomPassword } from '$lib/utils';
|
||||
import Container from '$lib/components/Utils/Container.svelte';
|
||||
|
||||
export let roomId: string;
|
||||
|
||||
const minPasswordLength = 4;
|
||||
let r = '';
|
||||
|
||||
function onSubmit() {
|
||||
if (r != '' && r != null && r != undefined && r.length >= minPasswordLength) {
|
||||
enterRoomPassword(r, roomId);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Container heading="Enter Room Password">
|
||||
<form
|
||||
on:submit|preventDefault={() => onSubmit()}
|
||||
class="flex flex-col w-full">
|
||||
<label
|
||||
for="enterRoomPassword"
|
||||
class="label" />
|
||||
<input
|
||||
id="enterRoomPassword"
|
||||
type="password"
|
||||
name="password"
|
||||
class="input"
|
||||
bind:value={r}
|
||||
required />
|
||||
<button
|
||||
class="btn variant-filled-primary mt-3"
|
||||
type="submit">Enter Room Password</button>
|
||||
</form>
|
||||
</Container>
|
||||
Reference in New Issue
Block a user