Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion web_src/js/modules/errors.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
import {showGlobalErrorMessage} from './errors.ts';
import {isGiteaError, showGlobalErrorMessage} from './errors.ts';

test('isGiteaError', () => {
expect(isGiteaError('', '')).toBe(true);
expect(isGiteaError('moz-extension://abc/content.js', '')).toBe(false);
expect(isGiteaError('safari-extension://abc/content.js', '')).toBe(false);
expect(isGiteaError('safari-web-extension://abc/content.js', '')).toBe(false);
expect(isGiteaError('chrome-extension://abc/content.js', '')).toBe(false);
expect(isGiteaError('https://other-site.com/script.js', '')).toBe(false);
expect(isGiteaError('http://localhost:3000/some/page', '')).toBe(true);
expect(isGiteaError('http://localhost:3000/assets/js/index.abc123.js', '')).toBe(true);
expect(isGiteaError('', `Error\n at chrome-extension://abc/content.js:1:1`)).toBe(false);
expect(isGiteaError('', `Error\n at https://other-site.com/script.js:1:1`)).toBe(false);
expect(isGiteaError('', `Error\n at http://localhost:3000/assets/js/index.abc123.js:1:1`)).toBe(true);
expect(isGiteaError('http://localhost:3000/assets/js/index.js', `Error\n at chrome-extension://abc/content.js:1:1`)).toBe(false);
Comment thread
silverwind marked this conversation as resolved.
});

test('showGlobalErrorMessage', () => {
document.body.innerHTML = '<div class="page-content"></div>';
Expand Down
21 changes: 14 additions & 7 deletions web_src/js/modules/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,31 @@ export function showGlobalErrorMessage(msg: string, msgType: Intent = 'error') {
msgContainer.prepend(msgDiv);
}

// Detect whether an error originated from Gitea's own scripts, not from
// browser extensions or other external scripts.
const extensionRe = /(chrome|moz|safari(-web)?)-extension:\/\//;
export function isGiteaError(filename: string, stack: string): boolean {
if (extensionRe.test(filename) || extensionRe.test(stack)) return false;
const assetBaseUrl = new URL(`${window.config.assetUrlPrefix}/`, window.location.origin).href;
Comment thread
silverwind marked this conversation as resolved.
if (filename && !filename.startsWith(assetBaseUrl) && !filename.startsWith(window.location.origin)) return false;
if (stack && !stack.includes(assetBaseUrl)) return false;
Comment thread
silverwind marked this conversation as resolved.
return true;
}

export function processWindowErrorEvent({error, reason, message, type, filename, lineno, colno}: ErrorEvent & PromiseRejectionEvent) {
const err = error ?? reason;
const assetBaseUrl = String(new URL(`${window.config?.assetUrlPrefix ?? '/assets'}/`, window.location.origin));
const {runModeIsProd} = window.config ?? {};

// `error` and `reason` are not guaranteed to be errors. If the value is falsy, it is likely a
// non-critical event from the browser. We log them but don't show them to users. Examples:
// - https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver#observation_errors
// - https://github.com/mozilla-mobile/firefox-ios/issues/10817
// - https://github.com/go-gitea/gitea/issues/20240
if (!err) {
if (message) console.error(new Error(message));
if (runModeIsProd) return;
if (window.config.runModeIsProd) return;
}

// If the error stack trace does not include the base URL of our script assets, it likely came
// from a browser extension or inline script. Do not show such errors in production.
if (err instanceof Error && !err.stack?.includes(assetBaseUrl) && runModeIsProd) return;
// Filter out errors from browser extensions or other non-Gitea scripts.
if (!isGiteaError(filename ?? '', err?.stack ?? '')) return;
Comment thread
silverwind marked this conversation as resolved.

let msg = err?.message ?? message;
if (lineno) msg += ` (${filename} @ ${lineno}:${colno})`;
Expand Down
2 changes: 1 addition & 1 deletion web_src/js/vitest.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ await import('./globals.ts');
window.config = {
appUrl: 'http://localhost:3000/',
appSubUrl: '',
assetUrlPrefix: '',
assetUrlPrefix: '/assets',
sharedWorkerUri: '',
runModeIsProd: true,
customEmojis: {},
Expand Down