Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat]: Auto-clear localStorage and sessionStorage #611

Open
mcaskill opened this issue Dec 21, 2023 · 1 comment
Open

[Feat]: Auto-clear localStorage and sessionStorage #611

mcaskill opened this issue Dec 21, 2023 · 1 comment
Labels
enhancement New feature or request
Milestone

Comments

@mcaskill
Copy link

Description

Are there any plans to support erasing records from localStorage (and sessionStorage)?

Thank you for your work on this plugin.

Proposed solution

This would involve modifying the cookie helper functions to extract keys from the Storage instances, filter matching cookies, and remove them.

The internal implementation wouldn't be too complicated to add (see example below). I just don't know how this should be configurable for users integrating this plugin.

Option 1: `[category].autoClear.clear*Storage`
CookieConsent.run({
	categories: {
		analytics: {
			autoClear: {
				clearLocalStorage: true,
				clearSessionStorage: true,
				cookies: [
					{
						name: '_uetsid'
					}
				]
			}
		}
	}
})
Option 2: `[category].autoClear.cookies[].clear*Storage`
CookieConsent.run({
	categories: {
		analytics: {
			autoClear: {
				cookies: [
					{
						name: '_uetsid',
						localStorage: true,
						sessionStorage: true
					}
				]
			}
		}
	}
})
Option 3: `[category].autoClear.*Storage[]`
CookieConsent.run({
	categories: {
		analytics: {
			autoClear: {
				cookies: [
					{
						name: '_uetsid'
					}
				],
				localStorage: [
					{
						name: '_uetsid'
					}
				],
				sessionStorage: [
					{
						name: '_uetsid'
					}
				]
			}
		}
	}
})

The following is a stripped down working example I've tested on a client project (that does not implement the aformentioned configuration variants):

import { isLocalStorageAvailable, isSessionStorageAvailable } from '../utils/environment.js';
import * as CookieConsent from 'vanilla-cookieconsent';

CookieConsent.run({
	// ...
	onConsent: () => {
		toggleCategoryAnalytics();
	},
	onChange: ({ changedCategories }) => {
		if (changedCategories.includes('analytics')) {
			toggleCategoryAnalytics();
		}
	},
});

function toggleCategoryAnalytics() {
	const isAccepted = CookieConsent?.acceptedCategory('analytics');

	window.dataLayer?.push([ 'consent', 'update', {
		'analytics_storage': (isAccepted ? 'granted' : 'denied'),
	} ]);

	if (!isAccepted) {
		const cookies = CookieConsent.getConfig('categories')?.analytics?.autoClear?.cookies;
		if (cookies.length) {
			eraseStorageItems(cookies);
		}
	}
}

function eraseStorageItems(cookies) {
	let localStorageKeys;
	let sessionStorageKeys;

	for (const { name: cookieName } of cookies) {
		if (isLocalStorageAvailable()) {
			localStorageKeys ??= getAllStorageKeys(window.localStorage);

			const foundCookies = findMatchingCookies(localStorageKeys, cookieName);
			for (const foundCookie of foundCookies) {
				window.localStorage.removeItem(foundCookie);
			}
		}

		if (isSessionStorageAvailable()) {
			sessionStorageKeys ??= getAllStorageKeys(window.sessionStorage);

			const foundCookies = findMatchingCookies(sessionStorageKeys, cookieName);
			for (const foundCookie of foundCookies) {
				window.sessionStorage.removeItem(foundCookie);
			}
		}
	}
}

/**
 * This function is copied from `findMatchingCookies()` from
 * {@link https://github.com/orestbida/cookieconsent/blob/v3.0.0-rc.17/src/utils/cookies.js vanilla-cookieconsent}.
 *
 * @param {string[]} allCookies
 * @param {string}   cookieName
 */
function findMatchingCookies(allCookies, cookieName) {
	// ...
}

/**
 * Returns array with all the cookie names.
 *
 * This function is based on `getAllCookies()` from
 * {@link https://github.com/orestbida/cookieconsent/blob/v3.0.0-rc.17/src/utils/cookies.js vanilla-cookieconsent}.
 *
 * @param   {Storage} storage
 * @param   {?RegExp} [regex]
 * @returns {string[]}
 */
function getAllStorageKeys(storage, regex) {
	/**
	 * @type {string[]}
	 */
	const cookieNames = [];

	/**
	 * Save only the item names
	 */
	for (const name of Object.keys(storage)) {
		if (regex) {
			try {
				regex.test(name) && cookieNames.push(name);
			// eslint-disable-next-line no-empty
			} catch (e) {}
		} else {
			cookieNames.push(name);
		}
	}

	return cookieNames;
}

Additional details

No response

@mcaskill mcaskill added enhancement New feature or request triage yet to be reviewed labels Dec 21, 2023
@orestbida
Copy link
Owner

I think adding an option to delete items in localstorage is useful, but I don't agree on session storage ones, since they are deleted at the end of the browsing session.

@orestbida orestbida removed the triage yet to be reviewed label Feb 28, 2024
@orestbida orestbida added this to the v3.1.0 milestone Feb 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants