Skip to content

Commit

Permalink
fix(offline): clear SWR caches betwen users
Browse files Browse the repository at this point in the history
  • Loading branch information
KaiVandivier committed Oct 24, 2022
1 parent ddcc521 commit 1e0131b
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 15 deletions.
18 changes: 12 additions & 6 deletions services/offline/src/lib/__tests__/clear-sensitive-caches.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,18 @@ import {
const makeCachesDeleteMock = (keys: string[]) => {
return jest
.fn()
.mockImplementation((key) => Promise.resolve(keys.includes(key)))
.mockImplementation(key => Promise.resolve(keys.includes(key)))
}

const keysMockDefault = jest.fn().mockImplementation(async () => [])
const deleteMockDefault = makeCachesDeleteMock([])
const cachesDefault = {
keys: keysMockDefault,
delete: deleteMockDefault,
// the following to satisfy types:
has: () => Promise.resolve(true),
open: () => Promise.resolve(new Cache()),
match: () => Promise.resolve(new Response()),
}
window.caches = cachesDefault

Expand Down Expand Up @@ -53,6 +57,7 @@ it('returns false if caches.keys throws', async () => {
throw new Error('Security Error')
})
window.caches = {
...cachesDefault,
keys: spy,
}

Expand All @@ -63,20 +68,21 @@ it('returns false if caches.keys throws', async () => {
})

it('clears potentially sensitive caches', async () => {
const testKeys = ['cache1', 'cache2', 'app-shell']
const testKeys = ['cache1', 'cache2', 'app-shell', 'other-assets']
const keysMock = jest
.fn()
.mockImplementation(() => Promise.resolve(testKeys))
const deleteMock = makeCachesDeleteMock(testKeys)
window.caches = { keys: keysMock, delete: deleteMock }
window.caches = { ...cachesDefault, keys: keysMock, delete: deleteMock }

const cachesDeleted = await clearSensitiveCaches()
expect(cachesDeleted).toBe(true)

expect(deleteMock).toHaveBeenCalledTimes(3)
expect(deleteMock).toHaveBeenCalledTimes(4)
expect(deleteMock.mock.calls[0][0]).toBe('cache1')
expect(deleteMock.mock.calls[1][0]).toBe('cache2')
expect(deleteMock.mock.calls[2][0]).toBe('app-shell')
expect(deleteMock.mock.calls[3][0]).toBe('other-assets')
})

it('preserves keepable caches', async () => {
Expand All @@ -93,11 +99,11 @@ it('preserves keepable caches', async () => {

await clearSensitiveCaches()

expect(deleteMockDefault).toHaveBeenCalledTimes(3)
expect(deleteMockDefault).toHaveBeenCalledTimes(4)
expect(deleteMockDefault.mock.calls[0][0]).toBe('cache1')
expect(deleteMockDefault.mock.calls[1][0]).toBe('cache2')
expect(deleteMockDefault.mock.calls[2][0]).toBe('app-shell')
expect(deleteMockDefault).not.toHaveBeenCalledWith('other-assets')
expect(deleteMockDefault.mock.calls[3][0]).toBe('other-assets')
expect(deleteMockDefault).not.toHaveBeenCalledWith(
'workbox-precache-v2-https://hey.howareya.now/'
)
Expand Down
17 changes: 8 additions & 9 deletions services/offline/src/lib/clear-sensitive-caches.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export const SECTIONS_STORE = 'sections-store'
// Non-sensitive caches that can be kept:
const KEEPABLE_CACHES = [
/^workbox-precache/, // precached static assets
/^other-assets/, // static assets cached at runtime - shouldn't be sensitive
]

declare global {
Expand Down Expand Up @@ -38,17 +37,17 @@ const clearDB = async (dbName: string): Promise<void> => {
return new Promise((resolve, reject) => {
// IndexedDB fun:
const openDBRequest = indexedDB.open(dbName)
openDBRequest.onsuccess = (e) => {
openDBRequest.onsuccess = e => {
const db = (e.target as IDBOpenDBRequest).result
const tx = db.transaction(SECTIONS_STORE, 'readwrite')
// When the transaction completes is when the operation is done:
tx.oncomplete = () => resolve()
tx.onerror = (e) => reject((e.target as IDBRequest).error)
tx.onerror = e => reject((e.target as IDBRequest).error)
const os = tx.objectStore(SECTIONS_STORE)
const clearReq = os.clear()
clearReq.onerror = (e) => reject((e.target as IDBRequest).error)
clearReq.onerror = e => reject((e.target as IDBRequest).error)
}
openDBRequest.onerror = (e) => {
openDBRequest.onerror = e => {
reject((e.target as IDBOpenDBRequest).error)
}
})
Expand Down Expand Up @@ -78,16 +77,16 @@ export async function clearSensitiveCaches(
// (Resolves to 'false' because this can't detect if anything was deleted):
clearDB(dbName).then(() => false),
// Remove caches if not in keepable list
...cacheKeys.map((key) => {
if (!KEEPABLE_CACHES.some((pattern) => pattern.test(key))) {
...cacheKeys.map(key => {
if (!KEEPABLE_CACHES.some(pattern => pattern.test(key))) {
return caches.delete(key)
}
return false
}),
]).then((responses) => {
]).then(responses => {
// Return true if any caches have been cleared
// (caches.delete() returns true if a cache is deleted successfully)
// PWA apps can reload to restore their app shell cache
return responses.some((response) => response)
return responses.some(response => response)
})
}

0 comments on commit 1e0131b

Please sign in to comment.