Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove dependency: dexie #45

Open
wants to merge 5 commits into
base: prod
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 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
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "defillama-extension",
"private": true,
"version": "0.0.8.2",
"version": "0.0.8.3",
"type": "module",
"description": "DefiLlama Extension",
"displayName": "DefiLlama",
Expand All @@ -18,8 +18,6 @@
"@emotion/react": "^11",
"@emotion/styled": "^11",
"@tanstack/react-query": "^4.8.0",
"dexie": "^3.2.2",
"dexie-react-hooks": "^1.1.1",
"fast-levenshtein": "^3.0.0",
"framer-motion": "^7.5.1",
"react": "^18.2.0",
Expand Down
147 changes: 4 additions & 143 deletions src/pages/background/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,9 @@ import maxPain from "@assets/img/memes/max-pain-128.png";
import que from "@assets/img/memes/que-128.png";
import upOnly from "@assets/img/memes/up-only-128.png";

import { Protocol, protocolsDb, allowedDomainsDb, blockedDomainsDb, fuzzyDomainsDb } from "../libs/db";
import {
PROTOCOLS_API,
METAMASK_LIST_CONFIG_API,
DEFILLAMA_DIRECTORY_API,
PROTOCOL_TVL_THRESHOLD,
} from "../libs/constants";
import { getStorage } from "../libs/helpers";
import { checkDomain } from "../libs/phishing-detector";

startupTasks();

async function getCurrentTab() {
const queryOptions = { active: true, currentWindow: true };
const [tab] = await Browser.tabs.query(queryOptions);
Expand All @@ -37,6 +28,10 @@ async function handlePhishingCheck() {
let reason = "Unknown website";
const tab = await getCurrentTab();
try {
if (!tab) {
console.log('Unable to get current tab');
return;
}
const url = tab.url;
if (url.startsWith("https://metamask.github.io/phishing-warning")) {
// already captured and redirected to metamask phishing warning page
Expand Down Expand Up @@ -90,95 +85,6 @@ async function handlePhishingCheck() {
}
}

export async function updateProtocolsDb() {
const raw = await fetch(PROTOCOLS_API).then((res) => res.json());
const protocols = (raw["protocols"]?.map((x: any) => ({
name: x.name,
url: x.url,
logo: x.logo,
category: x.category,
tvl: x.tvl,
})) ?? []) as Protocol[];
if (protocols.length === 0) {
console.log("updateProtocolsDb", "no protocols found");
return;
}
// empty db before updating
await protocolsDb.protocols.clear();
const result = await protocolsDb.protocols.bulkPut(protocols);
console.log("updateProtocolsDb", result);
}

export async function updateDomainDbs() {
console.log("updateDomainDbs", "start");
const rawProtocols = await fetch(PROTOCOLS_API).then((res) => res.json());
const protocols = (
(rawProtocols["protocols"]?.map((x: any) => ({
name: x.name,
url: x.url,
logo: x.logo,
category: x.category,
tvl: x.tvl || 0,
})) ?? []) as Protocol[]
).filter((x) => x.tvl >= PROTOCOL_TVL_THRESHOLD);
const protocolDomains = protocols
.map((x) => {
try {
return new URL(x.url).hostname.replace("www.", "");
} catch (error) {
console.log("updateDomainDbs", "error", error);
return null;
}
})
.filter((x) => x !== null)
.map((x) => ({ domain: x }));
const metamaskLists = (await fetch(METAMASK_LIST_CONFIG_API).then((res) => res.json())) as {
fuzzylist: string[];
whitelist: string[];
blacklist: string[];
};
const metamaskFuzzyDomains = metamaskLists.fuzzylist.map((x) => ({ domain: x }));
const metamaskAllowedDomains = metamaskLists.whitelist.map((x) => ({ domain: x }));
const metamaskBlockedDomains = metamaskLists.blacklist.map((x) => ({ domain: x }));
const rawDefillamaDirectory = (await fetch(DEFILLAMA_DIRECTORY_API).then((res) => res.json())) as {
version: number;
whitelist: string[];
blacklist?: string[];
fuzzylist?: string[];
};
const defillamaDomains = rawDefillamaDirectory.whitelist.map((x) => ({ domain: x }));
const defillamaBlockedDomains = rawDefillamaDirectory.blacklist?.map((x) => ({ domain: x })) ?? [];
const defillamaFuzzyDomains = rawDefillamaDirectory.fuzzylist?.map((x) => ({ domain: x })) ?? [];
const allowedDomains = [metamaskAllowedDomains, protocolDomains, defillamaDomains].flat();
if (allowedDomains.length === 0) {
console.log("allowedDomainsDb", "no allowed domains fetched, skipping update");
} else {
allowedDomainsDb.domains.clear();
allowedDomainsDb.domains.bulkPut(allowedDomains);
console.log("allowedDomainsDb", await allowedDomainsDb.domains.count());
}

const blockedDomains = [metamaskBlockedDomains, defillamaBlockedDomains].flat();
if (blockedDomains.length === 0) {
console.log("blockedDomainsDb", "no blocked domains fetched, skipping update");
} else {
blockedDomainsDb.domains.clear();
blockedDomainsDb.domains.bulkPut(blockedDomains);
console.log("blockedDomainsDb", await blockedDomainsDb.domains.count());
}

const fuzzyDomains = [metamaskFuzzyDomains, protocolDomains, defillamaDomains, defillamaFuzzyDomains].flat();
if (fuzzyDomains.length === 0) {
console.log("fuzzyDomainsDb", "no fuzzy domains fetched, skipping update");
} else {
fuzzyDomainsDb.domains.clear();
fuzzyDomainsDb.domains.bulkPut(fuzzyDomains);
console.log("fuzzyDomainsDb", await fuzzyDomainsDb.domains.count());
}

console.log("updateDomainDbs", "done");
}

// monitor updates to the tab, specifically when the user navigates to a new page (new url)
Browser.tabs.onUpdated.addListener(async (tabId, onUpdatedInfo, tab) => {
// console.log("onUpdated", onUpdatedInfo.status, onUpdatedInfo.url);
Expand All @@ -194,48 +100,3 @@ Browser.tabs.onActivated.addListener(async (onActivatedInfo) => {
await Browser.tabs.sendMessage(onActivatedInfo.tabId, { message: "TabActivated" });
await handlePhishingCheck();
});

async function setupUpdateProtocolsDb() {
console.log("setupUpdateProtocolsDb");
await Browser.alarms.clear("updateProtocolsDb");

console.log("setupUpdateProtocolsDb", "create");
await updateProtocolsDb();
Browser.alarms.create("updateProtocolsDb", { periodInMinutes: 4 * 60 }); // update once every 4 hours
}

async function setupUpdateDomainDbs() {
console.log("setupUpdateDomainDbs");
await Browser.alarms.clear("updateDomainDbs");

console.log("setupUpdateDomainDbs", "create");
await updateDomainDbs();
Browser.alarms.create("updateDomainDbs", { periodInMinutes: 4 * 60 }); // update once every 4 hours
}

function startupTasks() {
console.log("startupTasks", "start");
setupUpdateProtocolsDb();
setupUpdateDomainDbs();
Browser.action.setIcon({ path: cute });
console.log("startupTasks", "done");
}

Browser.runtime.onInstalled.addListener(() => {
startupTasks();
});

Browser.runtime.onStartup.addListener(() => {
startupTasks();
});

Browser.alarms.onAlarm.addListener(async (a) => {
switch (a.name) {
case "updateProtocolsDb":
await updateProtocolsDb();
break;
case "updateDomainDbs":
await updateDomainDbs();
break;
}
});
153 changes: 111 additions & 42 deletions src/pages/libs/db.ts
Original file line number Diff line number Diff line change
@@ -1,65 +1,134 @@
import Dexie, { Table } from "dexie";
import { fetchData } from './storage'
import { version } from '../../../package.json'
import Browser from "webextension-polyfill";
import cute from "@assets/img/memes/cute-128.png";

import {
PROTOCOLS_API,
METAMASK_LIST_CONFIG_API,
DEFILLAMA_DIRECTORY_API,
PROTOCOL_TVL_THRESHOLD,
} from "./constants";

export interface Protocol {
name: string;
url: string;
logo: string;
category: string;
tvl?: number;
}

export class ProtocolsDb extends Dexie {
protocols!: Table<Protocol>;

constructor() {
super("ProtocolsDb");
this.version(1).stores({
protocols: "name, category",
});
}
export const blockedDomainsDb: {
data: Set<string>
} = {
data: new Set()
}

export const protocolsDb = new ProtocolsDb();
export const fuzzyDomainsDb: {
data: string[]
} = {
data: []
}

export interface Domain {
domain: string;
export const allowedDomainsDb: {
data: Set<string>
} = {
data: new Set()
}

export class AllowedDomainsDb extends Dexie {
domains!: Table<Domain>;
const cacheKey = 'cache-v' + version

constructor() {
super("AllowedDomainsDb");
this.version(1).stores({
domains: "domain",
});
}
}
async function getData() {
console.time(cacheKey)
const rawProtocols = await fetch(PROTOCOLS_API).then((res) => res.json());
const protocols = (
(rawProtocols["protocols"]?.map((x: any) => ({
url: x.url,
tvl: x.tvl || 0,
})) ?? []) as Protocol[]
).filter((x) => x.tvl >= PROTOCOL_TVL_THRESHOLD);
const protocolDomains = protocols
.map((x) => {
try {
if (!x.url) return null;
return new URL(x.url).hostname.replace("www.", "");
} catch (error) {
console.log("updateDomainDbs", "error", error);
return null;
}
})
.filter((x) => x !== null)
console.log("updateDomainDbs", "protocolDomains", protocolDomains.length);
const metamaskLists = (await fetch(METAMASK_LIST_CONFIG_API).then((res) => res.json())) as {
fuzzylist: string[];
whitelist: string[];
blacklist: string[];
};
const metamaskFuzzyDomains = metamaskLists.fuzzylist;
const metamaskAllowedDomains = metamaskLists.whitelist;
const metamaskBlockedDomains = metamaskLists.blacklist;
const rawDefillamaDirectory = (await fetch(DEFILLAMA_DIRECTORY_API).then((res) => res.json())) as {
version: number;
whitelist: string[];
blacklist?: string[];
fuzzylist?: string[];
};
const defillamaDomains = rawDefillamaDirectory.whitelist;
const defillamaBlockedDomains = rawDefillamaDirectory.blacklist ?? [];
const defillamaFuzzyDomains = rawDefillamaDirectory.fuzzylist ?? [];
const allowedDomains = getUniqueItems(metamaskAllowedDomains, protocolDomains, defillamaDomains, ['x.com'])
console.log("allowedDomainsDb", allowedDomains.length);

export const allowedDomainsDb = new AllowedDomainsDb();
const blockedDomains = getUniqueItems(metamaskBlockedDomains, defillamaBlockedDomains)
console.log("blockedDomainsDb", blockedDomains.length);

export class FuzzyDomainsDb extends Dexie {
domains!: Table<Domain>;
const fuzzyDomains = getUniqueItems(metamaskFuzzyDomains, protocolDomains, defillamaDomains, defillamaFuzzyDomains)
console.log("fuzzyDomainsDb", await fuzzyDomains.length);

constructor() {
super("FuzzyDomainsDb");
this.version(1).stores({
domains: "domain",
});
console.timeEnd(cacheKey)
return {
allowedDomains,
blockedDomains,
fuzzyDomains,
}
}

export const fuzzyDomainsDb = new FuzzyDomainsDb();
function getUniqueItems(...arrays) {
const allItems = arrays.flat()
return [...new Set(allItems)]

export class BlockedDomainsDb extends Dexie {
domains!: Table<Domain>;
}

async function updateDb() {
const {
allowedDomains = [],
blockedDomains = [],
fuzzyDomains = [],
} = await fetchData({
key: cacheKey,
updateFrequency: 60 * 60 * 4, // update every 4 hours
getData,
})
allowedDomainsDb.data = new Set(allowedDomains)
blockedDomainsDb.data = new Set(blockedDomains)
fuzzyDomainsDb.data = fuzzyDomains
}

constructor() {
super("BlockedDomainsDb");
this.version(1).stores({
domains: "domain",
});
updateDb()
// setInterval(updateDb, 1000 * 6 * 10) // run every 10 minutes
Browser.alarms.create("updateDomainDbs", { periodInMinutes: 6 * 60 }); // update every 6 hours

Browser.alarms.onAlarm.addListener(async (a) => {
switch (a.name) {
case "updateDomainDbs":
await updateDb();
break;
}
})

async function startupTasks() {
console.time("startupTasks");
await updateDb();
Browser.action.setIcon({ path: cute });
console.timeEnd("startupTasks");
}

export const blockedDomainsDb = new BlockedDomainsDb();
Browser.runtime.onInstalled.addListener(startupTasks)
Browser.runtime.onStartup.addListener(startupTasks)
12 changes: 0 additions & 12 deletions src/pages/libs/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,6 @@
import { useCallback, useEffect, useState } from "react";
import { useLiveQuery } from "dexie-react-hooks";
import { Protocol, protocolsDb } from "./db";
import Browser from "webextension-polyfill";

/**
* Protocols data synced with IndexedDB and updated every 4 hours using Dexie.
*
* @returns {Protocol[]} protocols
*/
export const useProtocols = (): Protocol[] =>
useLiveQuery(async () => {
return await protocolsDb.protocols.toArray();
});

/**
* State synced with local storage. Updates itself when local storage changes based on event listener.
*
Expand Down
Loading