0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-02-01 05:22:54 +01:00

Forbid localStorage access in eslint (#36461)

Followup to
59f812bc1c,
enforce using our localStorage wrapper in eslint.

Also did a few tweaks in the eslint config, like removing the incomplete
list of globals, this is a non-issue with typescript.

---------

Signed-off-by: silverwind <me@silverwind.io>
This commit is contained in:
silverwind 2026-01-27 20:59:51 +01:00 committed by GitHub
parent 1463426a27
commit 224b7881d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 21 additions and 13 deletions

View File

@ -18,7 +18,18 @@ import {defineConfig, globalIgnores} from 'eslint/config';
const jsExts = ['js', 'mjs', 'cjs'] as const;
const tsExts = ['ts', 'mts', 'cts'] as const;
const restrictedSyntax = ['WithStatement', 'ForInStatement', 'LabeledStatement', 'SequenceExpression'];
const restrictedGlobals = [
{name: 'localStorage', message: 'Use `modules/user-settings.ts` instead.'},
{name: 'fetch', message: 'Use `modules/fetch.ts` instead.'},
];
const restrictedProperties = [
{object: 'window', property: 'localStorage', message: 'Use `modules/user-settings.ts` instead.'},
{object: 'globalThis', property: 'localStorage', message: 'Use `modules/user-settings.ts` instead.'},
{object: 'window', property: 'fetch', message: 'Use `modules/fetch.ts` instead.'},
{object: 'globalThis', property: 'fetch', message: 'Use `modules/fetch.ts` instead.'},
];
export default defineConfig([
globalIgnores([
@ -65,7 +76,7 @@ export default defineConfig([
'import-x/resolver': {'typescript': true},
},
rules: {
'@eslint-community/eslint-comments/disable-enable-pair': [2],
'@eslint-community/eslint-comments/disable-enable-pair': [0],
'@eslint-community/eslint-comments/no-aggregating-enable': [2],
'@eslint-community/eslint-comments/no-duplicate-disable': [2],
'@eslint-community/eslint-comments/no-restricted-disable': [0],
@ -555,9 +566,10 @@ export default defineConfig([
'no-redeclare': [0], // must be disabled for typescript overloads
'no-regex-spaces': [2],
'no-restricted-exports': [0],
'no-restricted-globals': [2, 'addEventListener', 'blur', 'close', 'closed', 'confirm', 'defaultStatus', 'defaultstatus', 'error', 'event', 'external', 'find', 'focus', 'frameElement', 'frames', 'history', 'innerHeight', 'innerWidth', 'isFinite', 'isNaN', 'length', 'locationbar', 'menubar', 'moveBy', 'moveTo', 'name', 'onblur', 'onerror', 'onfocus', 'onload', 'onresize', 'onunload', 'open', 'opener', 'opera', 'outerHeight', 'outerWidth', 'pageXOffset', 'pageYOffset', 'parent', 'print', 'removeEventListener', 'resizeBy', 'resizeTo', 'screen', 'screenLeft', 'screenTop', 'screenX', 'screenY', 'scroll', 'scrollbars', 'scrollBy', 'scrollTo', 'scrollX', 'scrollY', 'status', 'statusbar', 'stop', 'toolbar', 'top'],
'no-restricted-globals': [2, ...restrictedGlobals],
'no-restricted-properties': [2, ...restrictedProperties],
'no-restricted-imports': [0],
'no-restricted-syntax': [2, ...restrictedSyntax, {selector: 'CallExpression[callee.name="fetch"]', message: 'use modules/fetch.ts instead'}],
'no-restricted-syntax': [2, 'WithStatement', 'ForInStatement', 'LabeledStatement', 'SequenceExpression'],
'no-return-assign': [0],
'no-script-url': [2],
'no-self-assign': [2, {props: true}],
@ -923,12 +935,6 @@ export default defineConfig([
'vue/require-typed-ref': [2],
},
},
{
files: ['web_src/js/modules/fetch.ts', 'web_src/js/standalone/**/*'],
rules: {
'no-restricted-syntax': [2, ...restrictedSyntax],
},
},
{
files: ['**/*.test.ts', 'web_src/js/test/setup.ts'],
plugins: {vitest},

View File

@ -22,7 +22,7 @@ export function request(url: string, {method = 'GET', data, headers = {}, ...oth
headersMerged.set(name, value);
}
return fetch(url, {
return fetch(url, { // eslint-disable-line no-restricted-globals
method,
headers: headersMerged,
...other,

View File

@ -1,3 +1,4 @@
/* eslint-disable no-restricted-globals */
// Some people deploy Gitea under a subpath, so it needs prefix to avoid local storage key conflicts.
// And these keys are for user settings only, it also needs a specific prefix,
// in case in the future there are other uses of local storage, and/or we need to clear some keys when the quota is exceeded.

View File

@ -1,13 +1,14 @@
import SwaggerUI from 'swagger-ui-dist/swagger-ui-es-bundle.js';
import 'swagger-ui-dist/swagger-ui.css';
import {load as loadYaml} from 'js-yaml';
import {GET} from '../modules/fetch.ts';
window.addEventListener('load', async () => {
const elSwaggerUi = document.querySelector('#swagger-ui')!;
const url = elSwaggerUi.getAttribute('data-source')!;
let spec: any;
if (url) {
const res = await fetch(url);
const res = await GET(url);
spec = await res.json();
} else {
const elSpecContent = elSwaggerUi.querySelector<HTMLTextAreaElement>('.swagger-spec-content')!;

View File

@ -5,7 +5,7 @@ const pngPhys = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91
const pngEmpty = 'data:image/png;base64,';
async function dataUriToBlob(datauri: string) {
return await (await globalThis.fetch(datauri)).blob();
return await (await globalThis.fetch(datauri)).blob(); // eslint-disable-line no-restricted-properties
}
test('pngChunks', async () => {