Bug fixes and performance improvements

This commit is contained in:
2026-02-24 16:05:02 +01:00
parent da23868817
commit 7d614a2a7e
532 changed files with 639 additions and 523 deletions
+11 -14
View File
@@ -1,32 +1,29 @@
const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
const ipv6Regex = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,2}(:[0-9a-fA-F]{1,4}){1,5})|([0-9a-fA-F]{1,4}:)((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/;
const ipv6Regex = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,3}(:[0-9a-fA-F]{1,4}){1,4})|([0-9a-fA-F]{1,2}(:[0-9a-fA-F]{1,4}){1,5})|([0-9a-fA-F]{1,4}:)((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/;
export const IpUtils = {
isValidIP(ip: string): boolean {
if (!ip) return false;
const clean = ip.replace(/^\[|\]$/g, '');
return ipv4Regex.test(clean) || ipv6Regex.test(clean);
},
isLocalOrBogon(ip: string): boolean {
if (!ip) return false;
const clean = ip.replace(/^\[|\]$/g, '');
// IPv6 Local/Bogon
if (clean === '::1' || clean === '::') return true;
if (clean.toLowerCase().startsWith('fe80:')) return true;
if (clean.toLowerCase().startsWith('fc00:')) return true;
if (clean.toLowerCase().startsWith('fd00:')) return true;
if (!clean.includes('.')) return false;
// IPv4 Local/Bogon
const parts = clean.split('.').map(Number);
if (parts.length !== 4) return false;
if (parts[0] === 10) return true;
if (parts[0] === 192 && parts[1] === 168) return true;
if (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) return true;
if (parts[0] === 127) return true;
if (parts[0] === 169 && parts[1] === 254) return true;
if (clean.includes('.')) {
const parts = clean.split('.').map(Number);
if (parts[0] === 10) return true;
if (parts[0] === 192 && parts[1] === 168) return true;
if (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) return true;
if (parts[0] === 127) return true;
if (parts[0] === 169 && parts[1] === 254) return true;
}
return false;
}
+47 -21
View File
@@ -1,31 +1,57 @@
import type { HostInfo } from './types';
const CACHE_TTL = 1000 * 60 * 60 * 24;
export const StorageService = {
/**
* Returns the storage key for a specific tab with the required type prefix
*/
getKey(tabId: number): `session:${string}` {
return `session:host-info-${tabId}`;
async getTabState(tabId: number): Promise<TabState | null> {
const key = `tab_${tabId}`;
if (browser.storage.session) {
try {
const res = await browser.storage.session.get(key);
if (res[key]) return res[key] as TabState;
} catch { }
}
const res = await browser.storage.local.get(`session_${key}`);
return (res[`session_${key}`] as TabState) || null;
},
/**
* Save host info for a tab
*/
async set(tabId: number, data: HostInfo) {
await storage.setItem<HostInfo>(this.getKey(tabId), data);
async setTabState(tabId: number, state: TabState): Promise<void> {
const key = `tab_${tabId}`;
if (browser.storage.session) {
try {
await browser.storage.session.set({ [key]: state });
return;
} catch { }
}
await browser.storage.local.set({ [`session_${key}`]: state });
},
/**
* Get host info for a tab
*/
async get(tabId: number): Promise<HostInfo | null> {
return await storage.getItem<HostInfo>(this.getKey(tabId));
async removeTabState(tabId: number): Promise<void> {
const key = `tab_${tabId}`;
if (browser.storage.session) {
try {
await browser.storage.session.remove(key);
return;
} catch { }
}
await browser.storage.local.remove(`session_${key}`);
},
/**
* Clear data when a tab is closed
*/
async remove(tabId: number) {
await storage.removeItem(this.getKey(tabId));
async getGeoCache(ip: string): Promise<GeoData | null> {
const key = `geo_${ip.replace(/:/g, '_')}`;
const res = await browser.storage.local.get(key);
const entry = res[key] as CacheEntry | undefined;
if (!entry) return null;
if (Date.now() - entry.timestamp > CACHE_TTL) {
await browser.storage.local.remove(key);
return null;
}
return entry.data;
},
async setGeoCache(ip: string, data: GeoData): Promise<void> {
const key = `geo_${ip.replace(/:/g, '_')}`;
const entry: CacheEntry = { data, timestamp: Date.now() };
await browser.storage.local.set({ [key]: entry });
}
};
+14 -24
View File
@@ -1,38 +1,28 @@
export interface HostLocation {
export interface GeoData {
ip: string;
countryCode: string | null;
countryName: string | null;
city: string | null;
region: string | null;
timezone: string | null;
}
export interface HostNetwork {
ip: string;
asn: string | null;
org: string | null;
hostname: string | null;
asn: string | null;
timezone: string | null;
isLocal: boolean;
isBogon: boolean;
}
export interface HostInfo {
export type LoadingStatus = 'idle' | 'loading' | 'success' | 'error';
export interface TabState {
url: string;
domain: string;
network: HostNetwork | null;
location: HostLocation | null;
error: string | null;
loading: boolean;
isBrowserResource: boolean;
status: LoadingStatus;
data: GeoData | null;
errorMessage: string | null;
lastUpdated: number;
}
export interface GeoApiResponse {
ip: string;
hostname?: string;
city?: string;
region?: string;
country?: string;
loc?: string;
org?: string;
timezone?: string;
bogon?: boolean;
export interface CacheEntry {
data: GeoData;
timestamp: number;
}