mirror of
https://github.com/bitwarden/browser
synced 2026-01-28 07:13:29 +00:00
Added a fallback url when downloading phishing url list
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
export type PhishingResource = {
|
||||
name?: string;
|
||||
remoteUrl: string;
|
||||
/** Fallback URL to use if remoteUrl fails (e.g., due to SSL interception/cert issues) */
|
||||
fallbackUrl: string;
|
||||
checksumUrl: string;
|
||||
todayUrl: string;
|
||||
/** Matcher used to decide whether a given URL matches an entry from this resource */
|
||||
@@ -19,6 +21,8 @@ export const PHISHING_RESOURCES: Record<PhishingResourceType, PhishingResource[]
|
||||
{
|
||||
name: "Phishing.Database Domains",
|
||||
remoteUrl: "https://phish.co.za/latest/phishing-domains-ACTIVE.txt",
|
||||
fallbackUrl:
|
||||
"https://raw.githubusercontent.com/Phishing-Database/Phishing.Database/refs/heads/master/phishing-domains-ACTIVE.txt",
|
||||
checksumUrl:
|
||||
"https://raw.githubusercontent.com/Phishing-Database/checksums/refs/heads/master/phishing-domains-ACTIVE.txt.md5",
|
||||
todayUrl:
|
||||
@@ -46,6 +50,8 @@ export const PHISHING_RESOURCES: Record<PhishingResourceType, PhishingResource[]
|
||||
{
|
||||
name: "Phishing.Database Links",
|
||||
remoteUrl: "https://phish.co.za/latest/phishing-links-ACTIVE.txt",
|
||||
fallbackUrl:
|
||||
"https://raw.githubusercontent.com/Phishing-Database/Phishing.Database/refs/heads/master/phishing-links-ACTIVE.txt",
|
||||
checksumUrl:
|
||||
"https://raw.githubusercontent.com/Phishing-Database/checksums/refs/heads/master/phishing-links-ACTIVE.txt.md5",
|
||||
todayUrl:
|
||||
|
||||
@@ -160,6 +160,13 @@ export class PhishingDataService {
|
||||
|
||||
const resource = getPhishingResources(this.resourceType);
|
||||
|
||||
// Quick lookup: check direct presence of hostname in IndexedDB
|
||||
try {
|
||||
return await this.indexedDbService.hasUrl(url.hostname);
|
||||
} catch (err) {
|
||||
this.logService.error("[PhishingDataService] IndexedDB lookup via hasUrl failed", err);
|
||||
}
|
||||
|
||||
// If a custom matcher is provided, iterate stored entries and apply the matcher.
|
||||
if (resource && resource.match) {
|
||||
try {
|
||||
@@ -175,25 +182,29 @@ export class PhishingDataService {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO Should default lookup happen first for quick match
|
||||
// Default lookup: check presence of hostname in IndexedDB
|
||||
try {
|
||||
return await this.indexedDbService.hasUrl(url.hostname);
|
||||
} catch (err) {
|
||||
this.logService.error("[PhishingDataService] IndexedDB lookup failed", err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// [FIXME] Pull fetches into api service
|
||||
private async fetchPhishingChecksum(type: PhishingResourceType = PhishingResourceType.Domains) {
|
||||
const checksumUrl = getPhishingResources(type)!.checksumUrl;
|
||||
const response = await this.apiService.nativeFetch(new Request(checksumUrl));
|
||||
if (!response.ok) {
|
||||
throw new Error(`[PhishingDataService] Failed to fetch checksum: ${response.status}`);
|
||||
this.logService.debug(`[PhishingDataService] Fetching checksum from: ${checksumUrl}`);
|
||||
|
||||
try {
|
||||
const response = await this.apiService.nativeFetch(new Request(checksumUrl));
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`[PhishingDataService] Failed to fetch checksum: ${response.status} ${response.statusText}`,
|
||||
);
|
||||
}
|
||||
|
||||
return await response.text();
|
||||
} catch (error) {
|
||||
this.logService.error(
|
||||
`[PhishingDataService] Checksum fetch failed from ${checksumUrl}`,
|
||||
error,
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
return response.text();
|
||||
}
|
||||
|
||||
// [FIXME] Pull fetches into api service
|
||||
@@ -216,7 +227,7 @@ export class PhishingDataService {
|
||||
const webAddresses = devFlagValue("testPhishingUrls") as unknown[];
|
||||
if (webAddresses && webAddresses instanceof Array) {
|
||||
this.logService.debug(
|
||||
"[PhishingDetectionService] Dev flag enabled for testing phishing detection. Adding test phishing web addresses:",
|
||||
"[PhishingDataService] Dev flag enabled for testing phishing detection. Adding test phishing web addresses:",
|
||||
webAddresses,
|
||||
);
|
||||
return webAddresses as string[];
|
||||
@@ -225,11 +236,9 @@ export class PhishingDataService {
|
||||
}
|
||||
|
||||
private _getUpdatedMeta(): Observable<PhishingDataMeta> {
|
||||
// Use defer to
|
||||
return defer(() => {
|
||||
const now = Date.now();
|
||||
|
||||
// forkJoin kicks off both requests in parallel
|
||||
return forkJoin({
|
||||
applicationVersion: from(this.platformUtilsService.getApplicationVersion()),
|
||||
remoteChecksum: from(this.fetchPhishingChecksum(this.resourceType)),
|
||||
@@ -247,21 +256,41 @@ export class PhishingDataService {
|
||||
|
||||
// Streams the full phishing data set and saves it to IndexedDB
|
||||
private _updateFullDataSet() {
|
||||
this.logService.info("[PhishingDataService] Starting FULL update...");
|
||||
const resource = getPhishingResources(this.resourceType);
|
||||
|
||||
if (!resource?.remoteUrl) {
|
||||
return throwError(() => new Error("Invalid resource URL"));
|
||||
}
|
||||
|
||||
this.logService.info(`[PhishingDataService] Starting FULL update using ${resource.remoteUrl}`);
|
||||
return from(this.apiService.nativeFetch(new Request(resource.remoteUrl))).pipe(
|
||||
switchMap((response) => {
|
||||
if (!response.ok || !response.body) {
|
||||
return throwError(() => new Error(`Full fetch failed: ${response.statusText}`));
|
||||
return throwError(
|
||||
() =>
|
||||
new Error(
|
||||
`[PhishingDataService] Full fetch failed: ${response.status}, ${response.statusText}`,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return from(this.indexedDbService.saveUrlsFromStream(response.body));
|
||||
}),
|
||||
catchError((err: unknown) => {
|
||||
this.logService.error(
|
||||
`[PhishingDataService] Full dataset update failed using primary source ${err}`,
|
||||
);
|
||||
this.logService.warning(
|
||||
`[PhishingDataService] Falling back to: ${resource.fallbackUrl} (Note: Fallback data may be less up-to-date)`,
|
||||
);
|
||||
// Try fallback URL
|
||||
return from(this.apiService.nativeFetch(new Request(resource.fallbackUrl))).pipe(
|
||||
catchError((fallbackError: unknown) => {
|
||||
this.logService.error(`[PhishingDataService] Fallback source failed`);
|
||||
return throwError(() => fallbackError);
|
||||
}),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user