diff --git a/lib/client-utils.ts b/lib/client-utils.ts index a3471ea..4eb3342 100644 --- a/lib/client-utils.ts +++ b/lib/client-utils.ts @@ -20,13 +20,24 @@ export function useServerUrl(region?: string) { return serverUrl; } -export function encodePassphrase(bytes: Uint8Array) { - const binString = Array.from(bytes, (x) => String.fromCodePoint(x)).join(''); - return btoa(binString); +export function encodePassphrase(passphrase: string) { + return encodeURIComponent(passphrase); } export function decodePassphrase(base64String: string) { - const binString = atob(base64String); - // @ts-ignore - return Uint8Array.from(binString, (m) => m.codePointAt(0)); + return decodeURIComponent(base64String); +} + +export function generateRoomId(): string { + return `${randomString(4)}-${randomString(4)}`; +} + +export function randomString(length: number): string { + let result = ''; + const characters = 'abcdefghijklmnopqrstuvwxyz0123456789'; + const charactersLength = characters.length; + for (let i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + } + return result; } diff --git a/package.json b/package.json index 7ebe17a..c21bcdc 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "lint": "next lint" }, "dependencies": { - "@livekit/components-react": "1.1.7", + "@livekit/components-react": "1.1.8", "@livekit/components-styles": "1.0.6", "livekit-client": "1.13.2", "livekit-server-sdk": "1.2.6", diff --git a/pages/custom/index.tsx b/pages/custom/index.tsx index eb80620..96da862 100644 --- a/pages/custom/index.tsx +++ b/pages/custom/index.tsx @@ -16,13 +16,13 @@ export default function CustomRoomConnection() { const router = useRouter(); const { liveKitUrl, token } = router.query; - const hash = typeof window !== 'undefined' && window.location.hash; + const e2eePassphrase = typeof window !== 'undefined' && decodePassphrase(window.location.hash); const worker = typeof window !== 'undefined' && new Worker(new URL('livekit-client/e2ee-worker', import.meta.url)); const keyProvider = new ExternalE2EEKeyProvider(); - const e2eeEnabled = !!(hash && worker); + const e2eeEnabled = !!(e2eePassphrase && worker); const roomOptions = useMemo((): RoomOptions => { return { @@ -43,7 +43,7 @@ export default function CustomRoomConnection() { const room = useMemo(() => new Room(roomOptions), []); if (e2eeEnabled) { - keyProvider.setKey(decodePassphrase(hash.substring(1))); + keyProvider.setKey(e2eePassphrase); room.setE2EEEnabled(true); } diff --git a/pages/index.tsx b/pages/index.tsx index 008af42..8a9147d 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -2,7 +2,7 @@ import type { GetServerSideProps, InferGetServerSidePropsType } from 'next'; import { useRouter } from 'next/router'; import React, { ReactElement, useState } from 'react'; import styles from '../styles/Home.module.css'; -import { encodePassphrase } from '../lib/client-utils'; +import { encodePassphrase, generateRoomId, randomString } from '../lib/client-utils'; interface TabsProps { children: ReactElement[]; @@ -39,27 +39,12 @@ function Tabs(props: TabsProps) { function DemoMeetingTab({ label }: { label: string }) { const router = useRouter(); - const [e2ee, setE2ee] = useState(false); const startMeeting = () => { - if (e2ee) { - const phrase = encodePassphrase(crypto.getRandomValues(new Uint8Array(256))); - router.push(`/rooms/${generateRoomId()}#${phrase}`); - } else { - router.push(`/rooms/${generateRoomId()}`); - } + router.push(`/rooms/${generateRoomId()}`); }; return (

Try LiveKit Meet for free with our live demo project.

-
- setE2ee(ev.target.checked)} - > - -
@@ -69,7 +54,9 @@ function DemoMeetingTab({ label }: { label: string }) { function CustomConnectionTab({ label }: { label: string }) { const router = useRouter(); + const [e2ee, setE2ee] = useState(false); + const [sharedPassphrase, setSharedPassphrase] = useState(randomString(64)); const onSubmit: React.FormEventHandler = (event) => { event.preventDefault(); @@ -77,8 +64,9 @@ function CustomConnectionTab({ label }: { label: string }) { const serverUrl = formData.get('serverUrl'); const token = formData.get('token'); if (e2ee) { - const passphrase = encodePassphrase(crypto.getRandomValues(new Uint8Array(256))); - router.push(`/custom/?liveKitUrl=${serverUrl}&token=${token}#${passphrase}`); + router.push( + `/custom/?liveKitUrl=${serverUrl}&token=${token}#${encodePassphrase(sharedPassphrase)}`, + ); } else { router.push(`/custom/?liveKitUrl=${serverUrl}&token=${token}`); } @@ -103,15 +91,29 @@ function CustomConnectionTab({ label }: { label: string }) { rows={9} style={{ padding: '1px 2px', fontSize: 'inherit', lineHeight: 'inherit' }} /> -
- setE2ee(ev.target.checked)} - > - +
+
+ setE2ee(ev.target.checked)} + > + +
+ {e2ee && ( +
+ + setSharedPassphrase(ev.target.value)} + /> +
+ )}
+
@@ -179,17 +181,3 @@ const Home = ({ tabIndex }: InferGetServerSidePropsType { + return (await import('@livekit/components-react')).PreJoin; + }, + { ssr: false }, +); const Home: NextPage = () => { const router = useRouter(); const { name: roomName } = router.query; + const e2eePassphrase = + typeof window !== 'undefined' && decodePassphrase(location.hash.substring(1)); const [preJoinChoices, setPreJoinChoices] = useState(undefined); + + function handlePreJoinSubmit(values: LocalUserChoices) { + if (values.e2ee) { + location.hash = encodePassphrase(values.sharedPassphrase); + } + setPreJoinChoices(values); + } return ( <> @@ -45,18 +68,18 @@ const Home: NextPage = () => { > ) : (
- console.log('error while setting up prejoin', err)} defaults={{ username: '', videoEnabled: true, audioEnabled: true, + e2ee: !!e2eePassphrase, + sharedPassphrase: e2eePassphrase || randomString(64), }} - onSubmit={(values) => { - console.log('Joining with: ', values); - setPreJoinChoices(values); - }} - > + onSubmit={handlePreJoinSubmit} + showE2EEOptions={true} + >
)} @@ -85,12 +108,12 @@ const ActiveRoom = ({ roomName, userChoices, onLeave }: ActiveRoomProps) => { const liveKitUrl = useServerUrl(region as string | undefined); - const hash = typeof window !== 'undefined' && window.location.hash; const worker = typeof window !== 'undefined' && + userChoices.e2ee && new Worker(new URL('livekit-client/e2ee-worker', import.meta.url)); - const e2eeEnabled = !!(hash && worker); + const e2eeEnabled = !!(userChoices.e2ee && worker); const keyProvider = new ExternalE2EEKeyProvider(); const roomOptions = useMemo((): RoomOptions => { @@ -100,6 +123,7 @@ const ActiveRoom = ({ roomName, userChoices, onLeave }: ActiveRoomProps) => { resolution: hq === 'true' ? VideoPresets.h2160 : VideoPresets.h720, }, publishDefaults: { + dtx: false, videoSimulcastLayers: hq === 'true' ? [VideoPresets.h1080, VideoPresets.h720] @@ -123,7 +147,7 @@ const ActiveRoom = ({ roomName, userChoices, onLeave }: ActiveRoomProps) => { const room = useMemo(() => new Room(roomOptions), []); if (e2eeEnabled) { - keyProvider.setKey(decodePassphrase(hash.substring(1))); + keyProvider.setKey(decodePassphrase(userChoices.sharedPassphrase)); room.setE2EEEnabled(true); } const connectOptions = useMemo((): RoomConnectOptions => { diff --git a/yarn.lock b/yarn.lock index a86b94a..47ec07f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -101,10 +101,10 @@ loglevel "^1.8.1" rxjs "^7.8.0" -"@livekit/components-react@1.1.7": - version "1.1.7" - resolved "https://registry.yarnpkg.com/@livekit/components-react/-/components-react-1.1.7.tgz#f861350dc0df80fb3f027efa6a1706b9b203923e" - integrity sha512-wAOtzetPYMPrE6aA+ABzmLQA57IkvFC+qJiuvSWumbtzVmUZTaD56Y9T2d4F7/zwki3npbUQuABZmFaiMKChpg== +"@livekit/components-react@1.1.8": + version "1.1.8" + resolved "https://registry.yarnpkg.com/@livekit/components-react/-/components-react-1.1.8.tgz#34f67a6646bcd5c44d87d3fed5be5010b297f111" + integrity sha512-Ljlcqkgg7IqdQIDr7/ViEsL8GZkmSkoMC38hz3CkCcmHP+e8U4+4be2C2feiHb4hHw+tLd1DPuElyEWuTeiQKQ== dependencies: "@livekit/components-core" "0.6.15" "@react-hook/latest" "^1.0.3"