From 426ca7549b54a5c6753d38988c627f8e61d002c3 Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Thu, 29 Apr 2021 18:24:10 +0300 Subject: [PATCH] Support missing session storage (Fix Firefox Private Mode) --- src/lib/gramjs/sessions/CacheApiSession.js | 4 +- src/lib/gramjs/sessions/IdbSession.js | 2 +- .../gramjs/sessions/LocalStorageSession.js | 2 +- src/lib/gramjs/sessions/StorageSession.js | 22 +++- src/util/cacheApi.ts | 102 ++++++++++-------- 5 files changed, 84 insertions(+), 48 deletions(-) diff --git a/src/lib/gramjs/sessions/CacheApiSession.js b/src/lib/gramjs/sessions/CacheApiSession.js index 550dc0cb4..de31929f4 100644 --- a/src/lib/gramjs/sessions/CacheApiSession.js +++ b/src/lib/gramjs/sessions/CacheApiSession.js @@ -3,10 +3,10 @@ const StorageSession = require('./StorageSession') const CACHE_NAME = 'GramJs' class CacheApiSession extends StorageSession { - async delete() { + async _delete() { const request = new Request(this._storageKey) const cache = await self.caches.open(CACHE_NAME) - await cache.delete(request) + return cache.delete(request) } async _fetchFromCache() { diff --git a/src/lib/gramjs/sessions/IdbSession.js b/src/lib/gramjs/sessions/IdbSession.js index f60e6cd53..490494100 100644 --- a/src/lib/gramjs/sessions/IdbSession.js +++ b/src/lib/gramjs/sessions/IdbSession.js @@ -4,7 +4,7 @@ const idb = require('idb-keyval') const CACHE_NAME = 'GramJs' class IdbSession extends StorageSession { - async delete() { + async _delete() { return idb.del(`${CACHE_NAME}:${this._storageKey}`) } diff --git a/src/lib/gramjs/sessions/LocalStorageSession.js b/src/lib/gramjs/sessions/LocalStorageSession.js index abddd611a..77b522368 100644 --- a/src/lib/gramjs/sessions/LocalStorageSession.js +++ b/src/lib/gramjs/sessions/LocalStorageSession.js @@ -1,7 +1,7 @@ const StorageSession = require('./StorageSession') class LocalStorageSession extends StorageSession { - async delete() { + async _delete() { return localStorage.removeItem(this._storageKey) } diff --git a/src/lib/gramjs/sessions/StorageSession.js b/src/lib/gramjs/sessions/StorageSession.js index 303480a5e..4c87029be 100644 --- a/src/lib/gramjs/sessions/StorageSession.js +++ b/src/lib/gramjs/sessions/StorageSession.js @@ -32,7 +32,8 @@ class StorageSession extends MemorySession { } }) } catch (err) { - throw new Error(`Failed to retrieve or parse JSON from Cache for key ${this._storageKey}`) + console.warn('Failed to retrieve or parse session from storage') + console.warn(err) } } @@ -93,17 +94,34 @@ class StorageSession extends MemorySession { sessionData.hashes[dcId] = authKey._hash }) - await this._saveToCache(JSON.stringify(sessionData)) + try { + await this._saveToCache(JSON.stringify(sessionData)) + } catch (err) { + console.warn('Failed to update session in storage') + console.warn(err) + } } async delete() { + try { + return await this._delete() + } catch (err) { + console.warn('Failed to delete session from storage') + console.warn(err) + } + } + + // @abstract + async _delete() { throw new Error('Not Implemented') } + // @abstract async _fetchFromCache() { throw new Error('Not Implemented') } + // @abstract async _saveToCache(data) { throw new Error('Not Implemented') } diff --git a/src/util/cacheApi.ts b/src/util/cacheApi.ts index 0819a9628..cfe8aa495 100644 --- a/src/util/cacheApi.ts +++ b/src/util/cacheApi.ts @@ -12,38 +12,44 @@ export async function fetch(cacheName: string, key: string, type: Type) { return undefined; } - const request = new Request(key); - const cache = await cacheApi.open(cacheName); - const response = await cache.match(request); - if (!response) { - return undefined; - } - - switch (type) { - case Type.Text: - return response.text(); - case Type.Blob: { - const blob = await response.blob(); - - // Safari does not return correct Content-Type header for webp images. - if (key.substr(0, 7) === 'sticker') { - return new Blob([blob], { type: 'image/webp' }); - } - - // iOS Safari fails to preserve `type` in cache - if (!blob.type) { - const contentType = response.headers.get('Content-Type'); - if (contentType) { - return new Blob([blob], { type: contentType }); - } - } - - return blob; - } - case Type.Json: - return response.json(); - default: + try { + const request = new Request(key); + const cache = await cacheApi.open(cacheName); + const response = await cache.match(request); + if (!response) { return undefined; + } + + switch (type) { + case Type.Text: + return await response.text(); + case Type.Blob: { + const blob = await response.blob(); + + // Safari does not return correct Content-Type header for webp images. + if (key.substr(0, 7) === 'sticker') { + return new Blob([blob], { type: 'image/webp' }); + } + + // iOS Safari fails to preserve `type` in cache + if (!blob.type) { + const contentType = response.headers.get('Content-Type'); + if (contentType) { + return new Blob([blob], { type: contentType }); + } + } + + return blob; + } + case Type.Json: + return await response.json(); + default: + return undefined; + } + } catch (err) { + // eslint-disable-next-line no-console + console.warn(err); + return undefined; } } @@ -52,17 +58,29 @@ export async function save(cacheName: string, key: string, data: AnyLiteral | Bl return undefined; } - const cacheData = typeof data === 'string' || data instanceof Blob ? data : JSON.stringify(data); - const request = new Request(key); - const response = new Response(cacheData); - const cache = await cacheApi.open(cacheName); - return cache.put(request, response); -} - -export function clear(cacheName: string) { - if (!cacheApi) { + try { + const cacheData = typeof data === 'string' || data instanceof Blob ? data : JSON.stringify(data); + const request = new Request(key); + const response = new Response(cacheData); + const cache = await cacheApi.open(cacheName); + return await cache.put(request, response); + } catch (err) { + // eslint-disable-next-line no-console + console.warn(err); + return undefined; + } +} + +export async function clear(cacheName: string) { + try { + if (!cacheApi) { + return undefined; + } + + return await cacheApi.delete(cacheName); + } catch (err) { + // eslint-disable-next-line no-console + console.warn(err); return undefined; } - - return cacheApi.delete(cacheName); }