From 5bd05ea2b1bfe60bd8ef937faed386569d7207b8 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Sat, 4 Jul 2020 10:57:27 +0200 Subject: [PATCH 01/18] Allow modification used data only for specific fields --- config/default.json | 3 ++- core/modules/user/components/UserAccount.ts | 4 +++- core/modules/user/components/UserShippingDetails.ts | 4 +++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/config/default.json b/config/default.json index 9c9f5cd0d2..435e1f4bd2 100644 --- a/config/default.json +++ b/config/default.json @@ -717,7 +717,8 @@ "login_endpoint": "/api/user/login", "create_endpoint": "/api/user/create", "me_endpoint": "/api/user/me?token={{token}}", - "refresh_endpoint": "/api/user/refresh" + "refresh_endpoint": "/api/user/refresh", + "allowModification": ["firstname", "lastname", "email", "addresses"] }, "stock": { "synchronize": true, diff --git a/core/modules/user/components/UserAccount.ts b/core/modules/user/components/UserAccount.ts index b62cad6310..a82dbb8b84 100644 --- a/core/modules/user/components/UserAccount.ts +++ b/core/modules/user/components/UserAccount.ts @@ -1,4 +1,6 @@ import toString from 'lodash-es/toString' +import pick from 'lodash-es/pick' +import config from 'config' const Countries = require('@vue-storefront/core/i18n/resource/countries.json') export const UserAccount = { @@ -86,7 +88,7 @@ export const UserAccount = { !this.objectsEqual(this.userCompany, this.getUserCompany()) || (this.userCompany.company && !this.addCompany) ) { - updatedProfile = JSON.parse(JSON.stringify(this.$store.state.user.current)) + updatedProfile = pick(JSON.parse(JSON.stringify(this.$store.state.user.current)), [...config.users.allowModification, 'default_billing']) updatedProfile.firstname = this.currentUser.firstname updatedProfile.lastname = this.currentUser.lastname updatedProfile.email = this.currentUser.email diff --git a/core/modules/user/components/UserShippingDetails.ts b/core/modules/user/components/UserShippingDetails.ts index 8f9eeaa8b9..87671b5fde 100644 --- a/core/modules/user/components/UserShippingDetails.ts +++ b/core/modules/user/components/UserShippingDetails.ts @@ -1,4 +1,6 @@ import toString from 'lodash-es/toString' +import pick from 'lodash-es/pick' +import config from 'config' const Countries = require('@vue-storefront/i18n/resource/countries.json') export const UserShippingDetails = { @@ -80,7 +82,7 @@ export const UserShippingDetails = { updateDetails () { let updatedShippingDetails if (!this.objectsEqual(this.shippingDetails, this.getShippingDetails())) { - updatedShippingDetails = JSON.parse(JSON.stringify(this.$store.state.user.current)) + updatedShippingDetails = pick(JSON.parse(JSON.stringify(this.$store.state.user.current)), config.users.allowModification) let updatedShippingDetailsAddress = { firstname: this.shippingDetails.firstName, lastname: this.shippingDetails.lastName, From c4f1e1f796ba1f3c36ed9d5fe9efced2e559216b Mon Sep 17 00:00:00 2001 From: tkostuch Date: Sat, 4 Jul 2020 11:05:44 +0200 Subject: [PATCH 02/18] update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 139af122fb..0e0cc526e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- **IMPORTANT** for security reasons we added new config `users.allowModification`. + This can help to dissallow modifying fields that shouldn't be changed by user. + ### Changed / Improved ## [1.12.1] - 2020.06.22 From 4bd0b4b7e017e6a59e1debc08525d4e961634c87 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Sat, 4 Jul 2020 11:47:35 +0200 Subject: [PATCH 03/18] add helmet --- config/default.json | 3 +++ core/package.json | 1 + core/scripts/server.ts | 5 +++++ 3 files changed, 9 insertions(+) diff --git a/config/default.json b/config/default.json index 435e1f4bd2..e69b8e337e 100644 --- a/config/default.json +++ b/config/default.json @@ -66,6 +66,9 @@ "trace": { "enabled": false, "config": {} + }, + "helmet": { + "enabled": true } }, "initialResources": [ diff --git a/core/package.json b/core/package.json index faf03dfa35..6c46a332ff 100644 --- a/core/package.json +++ b/core/package.json @@ -12,6 +12,7 @@ "compression": "^1.7.4", "config": "^1.30.0", "express": "^4.14.0", + "helmet": "^3.23.3", "html-minifier": "^4.0.0", "lean-he": "^2.0.0", "localforage": "^1.7.2", diff --git a/core/scripts/server.ts b/core/scripts/server.ts index ddf44f6670..1dc1394777 100755 --- a/core/scripts/server.ts +++ b/core/scripts/server.ts @@ -20,6 +20,7 @@ serverHooksExecutors.afterProcessStarted(config.server) const express = require('express') const ms = require('ms') const request = require('request'); +const helmet = require('helmet') const cache = require('./utils/cache-instance') const apiStatus = require('./utils/api-status') @@ -137,6 +138,10 @@ const serve = (path, cache, options?) => express.static(resolve(path), Object.as const themeRoot = require('../build/theme-path') +if (config.server.helmet && config.server.helmet.enabled && isProd) { + app.use(helmet(config.server.helmet.config)) +} + app.use('/dist', serve('dist', true)) app.use('/assets', serve(themeRoot + '/assets', true)) app.use('/service-worker.js', serve('dist/service-worker.js', false, { From 4a45f1e0da1245312681c64f0b63d0f44a0b7c16 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Sat, 4 Jul 2020 11:49:36 +0200 Subject: [PATCH 04/18] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e0cc526e1..93a85610f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **IMPORTANT** for security reasons we added new config `users.allowModification`. This can help to dissallow modifying fields that shouldn't be changed by user. +- Add helmet - enabled by default, you can pass configuration by adding `config.server.helmet.config`. + More info about helmet configuration https://helmetjs.github.io/docs/ ### Changed / Improved From 00a565e5e22b5c89cffd47ed4382b910b7e424a4 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Sun, 12 Jul 2020 13:10:52 +0200 Subject: [PATCH 05/18] send user token in header --- config/default.json | 3 ++- core/data-resolver/ProductService.ts | 7 +++-- core/lib/sync/task.ts | 40 +++++++++++++++++++++++----- 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/config/default.json b/config/default.json index e69b8e337e..a1b1eaec22 100644 --- a/config/default.json +++ b/config/default.json @@ -721,7 +721,8 @@ "create_endpoint": "/api/user/create", "me_endpoint": "/api/user/me?token={{token}}", "refresh_endpoint": "/api/user/refresh", - "allowModification": ["firstname", "lastname", "email", "addresses"] + "allowModification": ["firstname", "lastname", "email", "addresses"], + "tokenInHeader": false }, "stock": { "synchronize": true, diff --git a/core/data-resolver/ProductService.ts b/core/data-resolver/ProductService.ts index 2b839e8fc1..3dd1622d38 100644 --- a/core/data-resolver/ProductService.ts +++ b/core/data-resolver/ProductService.ts @@ -104,7 +104,7 @@ const getProductRenderList = async ({ url = `${url}&userGroupId=${userGroupId}` } - if (token) { + if (token && !config.users.tokenInHeader) { url = `${url}&token=${token}` } @@ -112,7 +112,10 @@ const getProductRenderList = async ({ const task = await TaskQueue.execute({ url, // sync the cart payload: { method: 'GET', - headers: { 'Content-Type': 'application/json' }, + headers: { + 'Content-Type': 'application/json', + ...(token && config.users.tokenInHeader ? { authorization: `Bearer ${token}` } : {}) + }, mode: 'cors' }, callback_event: 'prices-after-sync' diff --git a/core/lib/sync/task.ts b/core/lib/sync/task.ts index 7fe74eb26f..85f13978f4 100644 --- a/core/lib/sync/task.ts +++ b/core/lib/sync/task.ts @@ -15,6 +15,7 @@ import { serial } from '@vue-storefront/core/helpers' import config from 'config' import { onlineHelper } from '@vue-storefront/core/helpers' import { hasResponseError, getResponseMessage } from '@vue-storefront/core/lib/sync/helpers' +import queryString from 'query-string' export function _prepareTask (task) { const taskId = entities.uniqueEntityId(task) // timestamp as a order id is not the best we can do but it's enough @@ -29,6 +30,36 @@ function _sleep (time) { return new Promise((resolve) => setTimeout(resolve, time)) } +function getUrl (task, currentToken, currentCartId) { + let url = task.url + .replace('{{token}}', (currentToken == null) ? '' : currentToken) + .replace('{{cartId}}', (currentCartId == null) ? '' : currentCartId) + + url = processURLAddress(url); // use relative url paths + if (config.storeViews.multistore) { + url = adjustMultistoreApiUrl(url) + } + + if (config.users.tokenInHeader) { + const parsedUrl = queryString.parseUrl(url) + delete parsedUrl['query']['token'] + url = queryString.stringifyUrl(parsedUrl) + } + + return url +} + +function getPayload (task, currentToken) { + const payload = { + ...task.payload, + headers: { + ...task.payload.headers, + ...(config.users.tokenInHeader ? { authorization: `Bearer ${currentToken}` } : {}) + } + } + return payload +} + function _internalExecute (resolve, reject, task: Task, currentToken, currentCartId) { if (currentToken && rootStore.state.userTokenInvalidateLock > 0) { // invalidate lock set Logger.log('Waiting for rootStore.state.userTokenInvalidateLock to release for ' + task.url, 'sync')() @@ -52,14 +83,11 @@ function _internalExecute (resolve, reject, task: Task, currentToken, currentCar reject('Error executing sync task ' + task.url + ' the required cartId argument is null. Re-creating shopping cart synchro.') return } - let url = task.url.replace('{{token}}', (currentToken == null) ? '' : currentToken).replace('{{cartId}}', (currentCartId == null) ? '' : currentCartId) - url = processURLAddress(url); // use relative url paths - if (config.storeViews.multistore) { - url = adjustMultistoreApiUrl(url) - } + const url = getUrl(task, currentToken, currentCartId) + const payload = getPayload(task, currentToken) let silentMode = false Logger.info('Executing sync task ' + url, 'sync', task)() - return fetch(url, task.payload).then((response) => { + return fetch(url, payload).then((response) => { const contentType = response.headers.get('content-type') if (contentType && contentType.includes('application/json')) { return response.json() From 2bcc55a35482f53ceae54fd6c8016e1dcacd1c18 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Sun, 12 Jul 2020 13:12:42 +0200 Subject: [PATCH 06/18] update changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93a85610f2..f7a509cb54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,12 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -### Fixed - - **IMPORTANT** for security reasons we added new config `users.allowModification`. This can help to dissallow modifying fields that shouldn't be changed by user. - Add helmet - enabled by default, you can pass configuration by adding `config.server.helmet.config`. More info about helmet configuration https://helmetjs.github.io/docs/ +- Add config `users.tokenInHeader` which allows to send token in header instead in query. Require to set on true same config in vsf-api. + +### Fixed ### Changed / Improved From ee990efd7edca61c8aba51b6e69bddb8b5021cdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Rakowski?= Date: Wed, 15 Jul 2020 14:14:40 +0200 Subject: [PATCH 07/18] clear cache method added --- core/lib/storage-manager.ts | 13 ++++++++++++- core/modules/cart/helpers/cartCacheHandler.ts | 7 ++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/core/lib/storage-manager.ts b/core/lib/storage-manager.ts index 7619f81b1a..ae314b1dec 100644 --- a/core/lib/storage-manager.ts +++ b/core/lib/storage-manager.ts @@ -37,7 +37,10 @@ const StorageManager = { * @param item UniversalStorage driver */ set: function (collectionName: string, collectionInstance: UniversalStorage): UniversalStorage { - this.storageMap[collectionName] = collectionInstance + try { + this.storageMap[collectionName] = collectionInstance + } catch (e) { + } return collectionInstance }, /** @@ -59,6 +62,14 @@ const StorageManager = { } else { return this.storageMap[collectionName] } + }, + clear ({ keep }): any { + const promiseArray = Object.keys(this.storageMap).map((collectionName) => { + return keep.every(itemToKeep => collectionName !== itemToKeep) && this.storageMap[collectionName].clear().then(() => { + Logger.warn(`storeManager cleared: ${collectionName}`, `storeManager cleared: ${collectionName}`, `storeManager cleared: ${collectionName}`)() + }) + }) + return Promise.all(promiseArray) } } diff --git a/core/modules/cart/helpers/cartCacheHandler.ts b/core/modules/cart/helpers/cartCacheHandler.ts index 683d0cedc2..82e4c2c801 100644 --- a/core/modules/cart/helpers/cartCacheHandler.ts +++ b/core/modules/cart/helpers/cartCacheHandler.ts @@ -15,9 +15,14 @@ export function cartCacheHandlerFactory (Vue) { type.endsWith(types.CART_DEL_NON_CONFIRMED_ITEM) || type.endsWith(types.CART_UPD_ITEM_PROPS) ) { - return StorageManager.get('cart').setItem('current-cart', state.cart.cartItems).catch((reason) => { + const cacheHandler = () => StorageManager.get('cart').setItem('current-cart', state.cart.cartItems).catch(async (reason) => { + await StorageManager.clear({ + keep: ['user', 'cart'] + }) + cacheHandler() Logger.error(reason)() // it doesn't work on SSR }) // populate cache + return cacheHandler() } else if ( type.endsWith(types.CART_LOAD_CART_SERVER_TOKEN) ) { From d1f5d4b979a0d1f3a2f12d0a0cc5823759a2fe0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Rakowski?= Date: Wed, 15 Jul 2020 14:22:39 +0200 Subject: [PATCH 08/18] test --- core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts b/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts index b6a50c1852..95bf33252b 100644 --- a/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts +++ b/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts @@ -10,6 +10,11 @@ const StorageManager = { }, get (key) { return this[key] + }, + clear ({ keep }) { + return new Promise((resolve, reject) => { + resolve() + }) } }; const cartCacheHandlerFactory = require('../../../helpers/cartCacheHandler').cartCacheHandlerFactory From 2bed0c9113c7e0ea0b21e1e1954792c2d859abe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Rakowski?= Date: Wed, 15 Jul 2020 14:26:20 +0200 Subject: [PATCH 09/18] fix --- core/modules/cart/helpers/cartCacheHandler.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/modules/cart/helpers/cartCacheHandler.ts b/core/modules/cart/helpers/cartCacheHandler.ts index 82e4c2c801..c49bec0c56 100644 --- a/core/modules/cart/helpers/cartCacheHandler.ts +++ b/core/modules/cart/helpers/cartCacheHandler.ts @@ -15,14 +15,14 @@ export function cartCacheHandlerFactory (Vue) { type.endsWith(types.CART_DEL_NON_CONFIRMED_ITEM) || type.endsWith(types.CART_UPD_ITEM_PROPS) ) { - const cacheHandler = () => StorageManager.get('cart').setItem('current-cart', state.cart.cartItems).catch(async (reason) => { + const cacheHandler = () => StorageManager.get('cart').setItem('current-cart', state.cart.cartItems) + return cacheHandler().catch(async (reason) => { await StorageManager.clear({ keep: ['user', 'cart'] }) cacheHandler() Logger.error(reason)() // it doesn't work on SSR }) // populate cache - return cacheHandler() } else if ( type.endsWith(types.CART_LOAD_CART_SERVER_TOKEN) ) { From 02c6fb43b91910fbc55095912db0523b37507c0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Rakowski?= Date: Wed, 15 Jul 2020 14:34:08 +0200 Subject: [PATCH 10/18] fix --- core/lib/storage-manager.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/core/lib/storage-manager.ts b/core/lib/storage-manager.ts index ae314b1dec..f6d5205ee6 100644 --- a/core/lib/storage-manager.ts +++ b/core/lib/storage-manager.ts @@ -37,10 +37,7 @@ const StorageManager = { * @param item UniversalStorage driver */ set: function (collectionName: string, collectionInstance: UniversalStorage): UniversalStorage { - try { - this.storageMap[collectionName] = collectionInstance - } catch (e) { - } + this.storageMap[collectionName] = collectionInstance return collectionInstance }, /** From b608c7fb62e241f14979e02636d6aa66f6304cbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Rakowski?= Date: Wed, 15 Jul 2020 15:13:57 +0200 Subject: [PATCH 11/18] setItem handles memory overload --- core/lib/storage-manager.ts | 2 +- core/lib/store/storage.ts | 8 +++++++- core/modules/cart/helpers/cartCacheHandler.ts | 5 +---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/core/lib/storage-manager.ts b/core/lib/storage-manager.ts index f6d5205ee6..6a2246beb7 100644 --- a/core/lib/storage-manager.ts +++ b/core/lib/storage-manager.ts @@ -60,7 +60,7 @@ const StorageManager = { return this.storageMap[collectionName] } }, - clear ({ keep }): any { + clear ({ keep = [] }): any { const promiseArray = Object.keys(this.storageMap).map((collectionName) => { return keep.every(itemToKeep => collectionName !== itemToKeep) && this.storageMap[collectionName].clear().then(() => { Logger.warn(`storeManager cleared: ${collectionName}`, `storeManager cleared: ${collectionName}`, `storeManager cleared: ${collectionName}`)() diff --git a/core/lib/store/storage.ts b/core/lib/store/storage.ts index 042ebb0c25..c6c533b85e 100644 --- a/core/lib/store/storage.ts +++ b/core/lib/store/storage.ts @@ -2,6 +2,7 @@ import * as localForage from 'localforage' import { Logger } from '@vue-storefront/core/lib/logger' import { isServer } from '@vue-storefront/core/helpers' import cloneDeep from 'lodash-es/cloneDeep' +import { StorageManager } from '@vue-storefront/core/lib/storage-manager' const CACHE_TIMEOUT = 800 const CACHE_TIMEOUT_ITERATE = 2000 @@ -339,7 +340,12 @@ class LocalForageCacheDriver { callback(null, result) } isResolved = true - }).catch(err => { + }).catch(async err => { + if (err.name === 'QuotaExceededError' || err.name === 'NS_ERROR_DOM_QUOTA_REACHED') { + await StorageManager.clear({ + keep: ['user', 'cart'] + }) + } isResolved = true this._lastError = err throw err diff --git a/core/modules/cart/helpers/cartCacheHandler.ts b/core/modules/cart/helpers/cartCacheHandler.ts index c49bec0c56..44ddb3dbfa 100644 --- a/core/modules/cart/helpers/cartCacheHandler.ts +++ b/core/modules/cart/helpers/cartCacheHandler.ts @@ -17,11 +17,8 @@ export function cartCacheHandlerFactory (Vue) { ) { const cacheHandler = () => StorageManager.get('cart').setItem('current-cart', state.cart.cartItems) return cacheHandler().catch(async (reason) => { - await StorageManager.clear({ - keep: ['user', 'cart'] - }) - cacheHandler() Logger.error(reason)() // it doesn't work on SSR + cacheHandler() }) // populate cache } else if ( type.endsWith(types.CART_LOAD_CART_SERVER_TOKEN) From 46915a5781fa5da8a2d33aac387dae2098e214cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Rakowski?= Date: Wed, 15 Jul 2020 15:32:16 +0200 Subject: [PATCH 12/18] preserveDrivers in config, handle clear cache hidden --- config/default.json | 6 +++- core/lib/store/storage.ts | 35 +++++++++++-------- core/modules/cart/helpers/cartCacheHandler.ts | 4 +-- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/config/default.json b/config/default.json index 9c9f5cd0d2..5ddcad6183 100644 --- a/config/default.json +++ b/config/default.json @@ -701,7 +701,11 @@ "syncTasks": "LOCALSTORAGE", "ordersHistory": "LOCALSTORAGE", "checkout": "LOCALSTORAGE" - } + }, + "preserveDrivers": [ + "cart", + "user" + ] }, "reviews": { "create_endpoint": "/api/review/create" diff --git a/core/lib/store/storage.ts b/core/lib/store/storage.ts index c6c533b85e..db4cc20ccb 100644 --- a/core/lib/store/storage.ts +++ b/core/lib/store/storage.ts @@ -3,6 +3,7 @@ import { Logger } from '@vue-storefront/core/lib/logger' import { isServer } from '@vue-storefront/core/helpers' import cloneDeep from 'lodash-es/cloneDeep' import { StorageManager } from '@vue-storefront/core/lib/storage-manager' +import config from 'config' const CACHE_TIMEOUT = 800 const CACHE_TIMEOUT_ITERATE = 2000 @@ -335,21 +336,25 @@ class LocalForageCacheDriver { }) } else { let isResolved = false - const promise = this._localForageCollection.ready().then(() => this._localForageCollection.setItem(key, copiedValue).then(result => { - if (isCallbackCallable) { - callback(null, result) - } - isResolved = true - }).catch(async err => { - if (err.name === 'QuotaExceededError' || err.name === 'NS_ERROR_DOM_QUOTA_REACHED') { - await StorageManager.clear({ - keep: ['user', 'cart'] - }) - } - isResolved = true - this._lastError = err - throw err - })) + const handleSetItem = () => this._localForageCollection.setItem(key, copiedValue) + .then(result => { + if (isCallbackCallable) { + callback(null, result) + } + isResolved = true + }) + .catch(async err => { + if (err.name === 'QuotaExceededError' || err.name === 'NS_ERROR_DOM_QUOTA_REACHED') { + await StorageManager.clear({ + keep: config.localForage.preserveDrivers || [] + }) + handleSetItem() + } + isResolved = true + this._lastError = err + throw err + }) + const promise = this._localForageCollection.ready().then(handleSetItem) clearTimeout(this._cacheTimeouts.iterate) this._cacheTimeouts.setItem = setTimeout(() => { if (!isResolved) { // this is cache time out check diff --git a/core/modules/cart/helpers/cartCacheHandler.ts b/core/modules/cart/helpers/cartCacheHandler.ts index 44ddb3dbfa..683d0cedc2 100644 --- a/core/modules/cart/helpers/cartCacheHandler.ts +++ b/core/modules/cart/helpers/cartCacheHandler.ts @@ -15,10 +15,8 @@ export function cartCacheHandlerFactory (Vue) { type.endsWith(types.CART_DEL_NON_CONFIRMED_ITEM) || type.endsWith(types.CART_UPD_ITEM_PROPS) ) { - const cacheHandler = () => StorageManager.get('cart').setItem('current-cart', state.cart.cartItems) - return cacheHandler().catch(async (reason) => { + return StorageManager.get('cart').setItem('current-cart', state.cart.cartItems).catch((reason) => { Logger.error(reason)() // it doesn't work on SSR - cacheHandler() }) // populate cache } else if ( type.endsWith(types.CART_LOAD_CART_SERVER_TOKEN) From 2e1c132c823205436af7c3ecf8a1686da7d4c500 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Rakowski?= Date: Wed, 15 Jul 2020 15:40:04 +0200 Subject: [PATCH 13/18] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06f54358e3..8a0c48b99f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - remove deprecated value from attributesListQuery query - @gibkigonzo (#4572) - Fixed dutch translations - @1070rik (#4587) +- localForage memory overload fixed. `localForage.preserveDrivers` keeps values to be preserved from being cleared. - @prakowski ### Changed / Improved From c1cdc354a02a8231e46d2a8ee7fab289ffa43b87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Rakowski?= Date: Wed, 15 Jul 2020 15:46:14 +0200 Subject: [PATCH 14/18] dependency moved --- core/lib/storage-manager.ts | 4 ++-- core/lib/store/storage.ts | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/core/lib/storage-manager.ts b/core/lib/storage-manager.ts index 6a2246beb7..6f2dbb6fc5 100644 --- a/core/lib/storage-manager.ts +++ b/core/lib/storage-manager.ts @@ -60,9 +60,9 @@ const StorageManager = { return this.storageMap[collectionName] } }, - clear ({ keep = [] }): any { + clear (): any { const promiseArray = Object.keys(this.storageMap).map((collectionName) => { - return keep.every(itemToKeep => collectionName !== itemToKeep) && this.storageMap[collectionName].clear().then(() => { + return (config.localForage.preserveDrivers || []).every(itemToKeep => collectionName !== itemToKeep) && this.storageMap[collectionName].clear().then(() => { Logger.warn(`storeManager cleared: ${collectionName}`, `storeManager cleared: ${collectionName}`, `storeManager cleared: ${collectionName}`)() }) }) diff --git a/core/lib/store/storage.ts b/core/lib/store/storage.ts index db4cc20ccb..792c5d7c6f 100644 --- a/core/lib/store/storage.ts +++ b/core/lib/store/storage.ts @@ -3,7 +3,6 @@ import { Logger } from '@vue-storefront/core/lib/logger' import { isServer } from '@vue-storefront/core/helpers' import cloneDeep from 'lodash-es/cloneDeep' import { StorageManager } from '@vue-storefront/core/lib/storage-manager' -import config from 'config' const CACHE_TIMEOUT = 800 const CACHE_TIMEOUT_ITERATE = 2000 @@ -345,9 +344,7 @@ class LocalForageCacheDriver { }) .catch(async err => { if (err.name === 'QuotaExceededError' || err.name === 'NS_ERROR_DOM_QUOTA_REACHED') { - await StorageManager.clear({ - keep: config.localForage.preserveDrivers || [] - }) + await StorageManager.clear() handleSetItem() } isResolved = true From ad56da36151548ed801aeb637c43c2ef0630915d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Rakowski?= Date: Wed, 15 Jul 2020 15:47:46 +0200 Subject: [PATCH 15/18] fix --- core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts b/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts index 95bf33252b..f57bc3edeb 100644 --- a/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts +++ b/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts @@ -11,7 +11,7 @@ const StorageManager = { get (key) { return this[key] }, - clear ({ keep }) { + clear () { return new Promise((resolve, reject) => { resolve() }) From e4aa7112b08875d1783e2951a3ef3d2c2820cbef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Rakowski?= Date: Wed, 15 Jul 2020 16:00:36 +0200 Subject: [PATCH 16/18] proper type added --- core/lib/storage-manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/lib/storage-manager.ts b/core/lib/storage-manager.ts index 6f2dbb6fc5..f89c64ccf0 100644 --- a/core/lib/storage-manager.ts +++ b/core/lib/storage-manager.ts @@ -60,7 +60,7 @@ const StorageManager = { return this.storageMap[collectionName] } }, - clear (): any { + clear (): Promise { const promiseArray = Object.keys(this.storageMap).map((collectionName) => { return (config.localForage.preserveDrivers || []).every(itemToKeep => collectionName !== itemToKeep) && this.storageMap[collectionName].clear().then(() => { Logger.warn(`storeManager cleared: ${collectionName}`, `storeManager cleared: ${collectionName}`, `storeManager cleared: ${collectionName}`)() From 28dd3deac974dbc44ecc0f880d03f35f5ea89ef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Rakowski?= Date: Wed, 15 Jul 2020 16:53:56 +0200 Subject: [PATCH 17/18] naming improved --- CHANGELOG.md | 2 +- config/default.json | 2 +- core/lib/storage-manager.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a0c48b99f..92c325d0c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - remove deprecated value from attributesListQuery query - @gibkigonzo (#4572) - Fixed dutch translations - @1070rik (#4587) -- localForage memory overload fixed. `localForage.preserveDrivers` keeps values to be preserved from being cleared. - @prakowski +- localForage memory overload fixed. `localForage.preserveCollections` keeps names of collections to be preserved from being cleared. - @prakowski ### Changed / Improved diff --git a/config/default.json b/config/default.json index 5ddcad6183..5b040631b2 100644 --- a/config/default.json +++ b/config/default.json @@ -702,7 +702,7 @@ "ordersHistory": "LOCALSTORAGE", "checkout": "LOCALSTORAGE" }, - "preserveDrivers": [ + "preserveCollections": [ "cart", "user" ] diff --git a/core/lib/storage-manager.ts b/core/lib/storage-manager.ts index f89c64ccf0..23b2c1e635 100644 --- a/core/lib/storage-manager.ts +++ b/core/lib/storage-manager.ts @@ -62,7 +62,7 @@ const StorageManager = { }, clear (): Promise { const promiseArray = Object.keys(this.storageMap).map((collectionName) => { - return (config.localForage.preserveDrivers || []).every(itemToKeep => collectionName !== itemToKeep) && this.storageMap[collectionName].clear().then(() => { + return (config.localForage.preserveCollections || []).every(collectionToKeep => collectionName !== collectionToKeep) && this.storageMap[collectionName].clear().then(() => { Logger.warn(`storeManager cleared: ${collectionName}`, `storeManager cleared: ${collectionName}`, `storeManager cleared: ${collectionName}`)() }) }) From 67d9a4ae755c6328800856a2e8fa61b4f3aeb414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Rakowski?= Date: Thu, 16 Jul 2020 10:03:12 +0200 Subject: [PATCH 18/18] Redundant code removed --- core/modules/catalog/helpers/search.ts | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/core/modules/catalog/helpers/search.ts b/core/modules/catalog/helpers/search.ts index c35d70c8b9..2be2cf5aac 100644 --- a/core/modules/catalog/helpers/search.ts +++ b/core/modules/catalog/helpers/search.ts @@ -45,15 +45,7 @@ export const storeProductToCache = (product, cacheByKey) => { const cacheKey = getCacheKey(product, cacheByKey); const cache = StorageManager.get('elasticCache'); - cache - .setItem(cacheKey, product, null, config.products.disablePersistentProductsCache) - .catch(err => { - Logger.error('Cannot store cache for ' + cacheKey, err)(); - if (err.name === 'QuotaExceededError' || err.name === 'NS_ERROR_DOM_QUOTA_REACHED') { - // quota exceeded error - cache.clear(); // clear products cache if quota exceeded - } - }); + cache.setItem(cacheKey, product, null, config.products.disablePersistentProductsCache) }; export const preConfigureProduct = ({ product, populateRequestCacheTags }) => {