diff --git a/packages/presentation/src/sound.ts b/packages/presentation/src/sound.ts index 6aa8ec906f4..b705b86b889 100644 --- a/packages/presentation/src/sound.ts +++ b/packages/presentation/src/sound.ts @@ -4,7 +4,12 @@ import { getClient } from '.' import notification from '@hcengineering/notification' const sounds = new Map() -const context = new AudioContext() +let context: AudioContext | undefined + +function getAudioContext (): AudioContext { + context ??= new AudioContext() + return context +} export async function isNotificationAllowed (_class?: Ref>): Promise { if (_class === undefined) return false @@ -24,7 +29,7 @@ export async function prepareSound (key: string): Promise { const soundUrl = getMetadata(key as Asset) as string const rawAudio = await fetch(soundUrl) const rawBuffer = await rawAudio.arrayBuffer() - const decodedBuffer = await context.decodeAudioData(rawBuffer) + const decodedBuffer = await getAudioContext().decodeAudioData(rawBuffer) sounds.set(key as Asset, decodedBuffer) } catch (err) { @@ -46,6 +51,10 @@ export async function playSound (soundKey: string, loop = false): Promise<(() => } try { + const context = getAudioContext() + if (context.state === 'suspended') { + await context.resume() + } const audio = context.createBufferSource() audio.buffer = sound audio.loop = loop diff --git a/plugins/love-resources/src/utils.ts b/plugins/love-resources/src/utils.ts index 1870183ecb9..fa01526fec7 100644 --- a/plugins/love-resources/src/utils.ts +++ b/plugins/love-resources/src/utils.ts @@ -296,6 +296,10 @@ async function checkRecordAvailable (): Promise { }, 500) } else if (endpoint !== '') { const res = await fetch(concatLink(endpoint, '/checkRecordAvailable')) + if (!res.ok || !res.headers.get('content-type')?.includes('application/json')) { + isRecordingAvailable.set(false) + return + } const result = await res.json() isRecordingAvailable.set(result) } else { diff --git a/plugins/notification-resources/src/utils.ts b/plugins/notification-resources/src/utils.ts index db9b2f71fb4..94bac12cc50 100644 --- a/plugins/notification-resources/src/utils.ts +++ b/plugins/notification-resources/src/utils.ts @@ -735,7 +735,7 @@ export function pushAvailable (): boolean { return ( 'serviceWorker' in navigator && 'PushManager' in window && - publicKey !== undefined && + isValidPushPublicKey(publicKey) && 'Notification' in window && Notification.permission !== 'denied' ) @@ -748,7 +748,7 @@ export async function subscribePush (): Promise { } const client = getClient() const publicKey = getPushPublicKey() - if ('serviceWorker' in navigator && 'PushManager' in window && publicKey !== undefined) { + if ('serviceWorker' in navigator && 'PushManager' in window && isValidPushPublicKey(publicKey)) { try { const loc = getCurrentLocation() let registration = await navigator.serviceWorker.getRegistration(`/${loc.path[0]}/${loc.path[1]}`) @@ -763,7 +763,7 @@ export async function subscribePush (): Promise { if (current == null) { const subscription = await registration.pushManager.subscribe({ userVisibleOnly: true, - applicationServerKey: publicKey + applicationServerKey: urlBase64ToUint8Array(publicKey) }) await client.createDoc(notification.class.PushSubscription, core.space.Workspace, { user: getCurrentAccount().uuid, @@ -808,6 +808,30 @@ function getPushPublicKey (): string | undefined { return publicKey.trim() !== '' ? publicKey : undefined } +function isValidPushPublicKey (publicKey: string | undefined): publicKey is string { + if (publicKey === undefined || publicKey.trim() === '') return false + + try { + const key = urlBase64ToUint8Array(publicKey) + return key.length === 65 && key[0] === 4 + } catch { + return false + } +} + +function urlBase64ToUint8Array (value: string): Uint8Array { + const padding = '='.repeat((4 - (value.length % 4)) % 4) + const base64 = `${value}${padding}`.replace(/-/g, '+').replace(/_/g, '/') + const rawData = atob(base64) + const outputArray = new Uint8Array(rawData.length) + + for (let i = 0; i < rawData.length; ++i) { + outputArray[i] = rawData.charCodeAt(i) + } + + return outputArray +} + async function cleanTag (_id: Ref): Promise { const client = getClient() const notifications = await client.findAll(notification.class.BrowserNotification, {