uBlock/assets/resources/localstorage.js

238 lines
7.7 KiB
JavaScript

/*******************************************************************************
uBlock Origin - a comprehensive, efficient content blocker
Copyright (C) 2019-present Raymond Hill
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
Home: https://github.com/gorhill/uBlock
The scriptlets below are meant to be injected only into a
web page context.
*/
import { getSafeCookieValuesFn } from './cookie.js';
import { registerScriptlet } from './base.js';
import { safeSelf } from './safe-self.js';
/******************************************************************************/
export function getAllLocalStorageFn(which = 'localStorage') {
const storage = self[which];
const out = [];
for ( let i = 0; i < storage.length; i++ ) {
const key = storage.key(i);
const value = storage.getItem(key);
return { key, value };
}
return out;
}
registerScriptlet(getAllLocalStorageFn, {
name: 'get-all-local-storage.fn',
});
/******************************************************************************/
export function setLocalStorageItemFn(
which = 'local',
trusted = false,
key = '',
value = '',
) {
if ( key === '' ) { return; }
// For increased compatibility with AdGuard
if ( value === 'emptyArr' ) {
value = '[]';
} else if ( value === 'emptyObj' ) {
value = '{}';
}
const trustedValues = [
'',
'undefined', 'null',
'{}', '[]', '""',
'$remove$',
...getSafeCookieValuesFn(),
];
if ( trusted ) {
if ( value.includes('$now$') ) {
value = value.replaceAll('$now$', Date.now());
}
if ( value.includes('$currentDate$') ) {
value = value.replaceAll('$currentDate$', `${Date()}`);
}
if ( value.includes('$currentISODate$') ) {
value = value.replaceAll('$currentISODate$', (new Date()).toISOString());
}
} else {
const normalized = value.toLowerCase();
const match = /^("?)(.+)\1$/.exec(normalized);
const unquoted = match && match[2] || normalized;
if ( trustedValues.includes(unquoted) === false ) {
if ( /^-?\d+$/.test(unquoted) === false ) { return; }
const n = parseInt(unquoted, 10) || 0;
if ( n < -32767 || n > 32767 ) { return; }
}
}
try {
const storage = self[`${which}Storage`];
if ( value === '$remove$' ) {
const safe = safeSelf();
const pattern = safe.patternToRegex(key, undefined, true );
const toRemove = [];
for ( let i = 0, n = storage.length; i < n; i++ ) {
const key = storage.key(i);
if ( pattern.test(key) ) { toRemove.push(key); }
}
for ( const key of toRemove ) {
storage.removeItem(key);
}
} else {
storage.setItem(key, `${value}`);
}
} catch(ex) {
}
}
registerScriptlet(setLocalStorageItemFn, {
name: 'set-local-storage-item.fn',
dependencies: [
getSafeCookieValuesFn,
safeSelf,
],
});
/******************************************************************************/
export function removeCacheStorageItem(
cacheNamePattern = '',
requestPattern = ''
) {
if ( cacheNamePattern === '' ) { return; }
const safe = safeSelf();
const logPrefix = safe.makeLogPrefix('remove-cache-storage-item', cacheNamePattern, requestPattern);
const cacheStorage = self.caches;
if ( cacheStorage instanceof Object === false ) { return; }
const reCache = safe.patternToRegex(cacheNamePattern, undefined, true);
const reRequest = safe.patternToRegex(requestPattern, undefined, true);
cacheStorage.keys().then(cacheNames => {
for ( const cacheName of cacheNames ) {
if ( reCache.test(cacheName) === false ) { continue; }
if ( requestPattern === '' ) {
cacheStorage.delete(cacheName).then(result => {
if ( safe.logLevel > 1 ) {
safe.uboLog(logPrefix, `Deleting ${cacheName}`);
}
if ( result !== true ) { return; }
safe.uboLog(logPrefix, `Deleted ${cacheName}: ${result}`);
});
continue;
}
cacheStorage.open(cacheName).then(cache => {
cache.keys().then(requests => {
for ( const request of requests ) {
if ( reRequest.test(request.url) === false ) { continue; }
if ( safe.logLevel > 1 ) {
safe.uboLog(logPrefix, `Deleting ${cacheName}/${request.url}`);
}
cache.delete(request).then(result => {
if ( result !== true ) { return; }
safe.uboLog(logPrefix, `Deleted ${cacheName}/${request.url}: ${result}`);
});
}
});
});
}
});
}
registerScriptlet(removeCacheStorageItem, {
name: 'remove-cache-storage-item.fn',
world: 'ISOLATED',
dependencies: [
safeSelf,
],
});
/*******************************************************************************
*
* set-local-storage-item.js
* set-session-storage-item.js
*
* Set a local/session storage entry to a specific, allowed value.
*
* Reference:
* https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/set-local-storage-item.js
* https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/set-session-storage-item.js
*
**/
export function setLocalStorageItem(key = '', value = '') {
setLocalStorageItemFn('local', false, key, value);
}
registerScriptlet(setLocalStorageItem, {
name: 'set-local-storage-item.js',
world: 'ISOLATED',
dependencies: [
setLocalStorageItemFn,
],
});
export function setSessionStorageItem(key = '', value = '') {
setLocalStorageItemFn('session', false, key, value);
}
registerScriptlet(setSessionStorageItem, {
name: 'set-session-storage-item.js',
world: 'ISOLATED',
dependencies: [
setLocalStorageItemFn,
],
});
/*******************************************************************************
*
* trusted-set-local-storage-item.js
*
* Set a local storage entry to an arbitrary value.
*
* Reference:
* https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/trusted-set-local-storage-item.js
*
**/
export function trustedSetLocalStorageItem(key = '', value = '') {
setLocalStorageItemFn('local', true, key, value);
}
registerScriptlet(trustedSetLocalStorageItem, {
name: 'trusted-set-local-storage-item.js',
requiresTrust: true,
world: 'ISOLATED',
dependencies: [
setLocalStorageItemFn,
],
});
export function trustedSetSessionStorageItem(key = '', value = '') {
setLocalStorageItemFn('session', true, key, value);
}
registerScriptlet(trustedSetSessionStorageItem, {
name: 'trusted-set-session-storage-item.js',
requiresTrust: true,
world: 'ISOLATED',
dependencies: [
setLocalStorageItemFn,
],
});