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

feat: add injected client to content script #69

Merged
merged 14 commits into from
Jul 4, 2024
Merged
23,858 changes: 23,858 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

Binary file modified plugins/twitter_profile/index.wasm
Binary file not shown.
2 changes: 1 addition & 1 deletion src/components/PluginInfo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export function PluginInfoModal(props: {
return (
<Modal
onClose={onClose}
className="custom-modal !rounded-none flex items-center justify-center gap-4"
className="custom-modal !rounded-none flex items-center justify-center gap-4 cursor-default"
>
<ModalHeader className="w-full p-2 border-gray-200 text-gray-500">
{header || (
Expand Down
10 changes: 5 additions & 5 deletions src/components/PluginList/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, {
ChangeEvent,
MouseEventHandler,
ReactElement,
useCallback,
Expand All @@ -20,13 +19,12 @@ import Icon from '../Icon';
import './index.scss';
import browser from 'webextension-polyfill';
import { ErrorModal } from '../ErrorModal';
import Modal, { ModalHeader, ModalContent, ModalFooter } from '../Modal/Modal';
import {
PluginInfoModal,
PluginInfoModalContent,
PluginInfoModalHeader,
} from '../PluginInfo';
import logo from '../../assets/img/icon-128.png';
import { getPluginConfigByHash } from '../../entries/Background/db';

export function PluginList(props: { className?: string }): ReactElement {
const hashes = usePluginHashes();
Expand All @@ -36,7 +34,9 @@ export function PluginList(props: { className?: string }): ReactElement {
}, []);

return (
<div className={classNames('flex flex-col flex-nowrap', props.className)}>
<div
className={classNames('flex flex-col flex-nowrap gap-1', props.className)}
>
{!hashes.length && (
<div className="flex flex-col items-center justify-center text-slate-400 cursor-default select-none">
<div>No available plugins</div>
Expand Down Expand Up @@ -82,7 +82,7 @@ export function Plugin(props: {

useEffect(() => {
(async function () {
setConfig(await fetchPluginConfigByHash(props.hash));
setConfig(await getPluginConfigByHash(props.hash));
})();
}, [props.hash]);

Expand Down
48 changes: 0 additions & 48 deletions src/entries/Background/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,6 @@ let RequestsLogs: {
[tabId: string]: NodeCache;
} = {};

let HeadersStore: {
[hostname: string]: NodeCache;
} = {};

let CookieStore: {
[hostname: string]: NodeCache;
} = {};

export const deleteCacheByTabId = (tabId: number) => {
delete RequestsLogs[tabId];
};
Expand All @@ -27,50 +19,10 @@ export const getCacheByTabId = (tabId: number): NodeCache => {
return RequestsLogs[tabId];
};

export const deleteHeadersByHost = (hostname: string) => {
delete HeadersStore[hostname];
};

export const getHeaderStoreByHost = (hostname: string): NodeCache => {
HeadersStore[hostname] =
HeadersStore[hostname] ||
new NodeCache({
stdTTL: 60 * 5, // default 5m TTL
maxKeys: 1000000,
});

return HeadersStore[hostname];
};

export const deleteCookiesByHost = (hostname: string) => {
delete CookieStore[hostname];
};

export const getCookieStoreByHost = (hostname: string): NodeCache => {
CookieStore[hostname] =
CookieStore[hostname] ||
new NodeCache({
stdTTL: 60 * 5, // default 5m TTL
maxKeys: 1000000,
});

return CookieStore[hostname];
};

export const clearRequestCache = () => {
RequestsLogs = {};
};

export const clearHeaderCache = () => {
HeadersStore = {};
};

export const clearCookieCache = () => {
CookieStore = {};
};

export const clearCache = () => {
clearRequestCache();
clearHeaderCache();
clearCookieCache();
};
166 changes: 161 additions & 5 deletions src/entries/Background/db.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Level } from 'level';
import type { RequestHistory } from './rpc';
import { PluginConfig, sha256 } from '../../utils/misc';
import { PluginConfig, PluginMetadata, sha256 } from '../../utils/misc';
import mutex from './mutex';
const charwise = require('charwise');

const db = new Level('./ext-db', {
export const db = new Level('./ext-db', {
valueEncoding: 'json',
});
const historyDb = db.sublevel<string, RequestHistory>('history', {
Expand All @@ -15,6 +16,18 @@ const pluginDb = db.sublevel<string, string>('plugin', {
const pluginConfigDb = db.sublevel<string, PluginConfig>('pluginConfig', {
valueEncoding: 'json',
});
const pluginMetadataDb = db.sublevel<string, PluginMetadata>('pluginMetadata', {
valueEncoding: 'json',
});
const connectionDb = db.sublevel<string, boolean>('connections', {
valueEncoding: 'json',
});
const cookiesDb = db.sublevel<string, boolean>('cookies', {
valueEncoding: 'json',
});
const headersDb = db.sublevel<string, boolean>('headers', {
valueEncoding: 'json',
});

export async function addNotaryRequest(
now = Date.now(),
Expand Down Expand Up @@ -127,14 +140,12 @@ export async function getNotaryRequests(): Promise<RequestHistory[]> {
export async function getNotaryRequest(
id: string,
): Promise<RequestHistory | null> {
return historyDb.get(id);
return historyDb.get(id).catch(() => null);
}

export async function getPluginHashes(): Promise<string[]> {
const retVal: string[] = [];
for await (const [key] of pluginDb.iterator()) {
// pluginDb.del(key);
// pluginConfigDb.del(key);
retVal.push(key);
}
return retVal;
Expand Down Expand Up @@ -205,6 +216,63 @@ export async function removePluginConfig(
return existing;
}

export async function getPlugins(): Promise<
(PluginConfig & { hash: string; metadata: PluginMetadata })[]
> {
const hashes = await getPluginHashes();
const ret: (PluginConfig & { hash: string; metadata: PluginMetadata })[] = [];
for (const hash of hashes) {
const config = await getPluginConfigByHash(hash);
const metadata = await getPluginMetadataByHash(hash);
if (config) {
ret.push({
...config,
hash,
metadata: metadata || {
filePath: '',
origin: '',
},
});
}
}
return ret;
}

export async function getPluginMetadataByHash(
hash: string,
): Promise<PluginMetadata | null> {
try {
const metadata = await pluginMetadataDb.get(hash);
return metadata;
} catch (e) {
return null;
}
}

export async function addPluginMetadata(
hash: string,
metadata: PluginMetadata,
): Promise<PluginMetadata | null> {
if (await getPluginMetadataByHash(hash)) {
return null;
}

await pluginMetadataDb.put(hash, metadata);
return metadata;
}

export async function removePluginMetadata(
hash: string,
): Promise<PluginMetadata | null> {
const existing = await pluginMetadataDb.get(hash);

if (!existing) return null;

await pluginMetadataDb.del(hash);

return existing;
}

export async function setNotaryRequestCid(
id: string,
cid: string,
Expand All @@ -222,3 +290,91 @@ export async function setNotaryRequestCid(

return newReq;
}

export async function setConnection(origin: string) {
if (await getConnection(origin)) return null;
await connectionDb.put(origin, true);
return true;
}

export async function setCookies(host: string, name: string, value: string) {
return mutex.runExclusive(async () => {
if (await getCookies(host, name)) return null;
await cookiesDb.sublevel(host).put(name, value);
return true;
});
}

export async function clearCookies(host: string) {
return mutex.runExclusive(async () => {
await cookiesDb.sublevel(host).clear();
return true;
});
}

export async function getCookies(host: string, name: string) {
try {
const existing = await cookiesDb.sublevel(host).get(name);
return existing;
} catch (e) {
return null;
}
}

export async function getCookiesByHost(host: string) {
const ret: { [key: string]: string } = {};
for await (const [key, value] of cookiesDb.sublevel(host).iterator()) {
ret[key] = value;
}
return ret;
}

export async function deleteConnection(origin: string) {
return mutex.runExclusive(async () => {
if (await getConnection(origin)) {
await connectionDb.del(origin);
}
});
}

export async function getConnection(origin: string) {
try {
const existing = await connectionDb.get(origin);
return existing;
} catch (e) {
return null;
}
}

export async function setHeaders(host: string, name: string, value?: string) {
if (!value) return null;
return mutex.runExclusive(async () => {
if (await getHeaders(host, name)) return null;
await headersDb.sublevel(host).put(name, value);
return true;
});
}

export async function clearHeaders(host: string) {
return mutex.runExclusive(async () => {
await headersDb.sublevel(host).clear();
return true;
});
}

export async function getHeaders(host: string, name: string) {
try {
const existing = await headersDb.sublevel(host).get(name);
return existing;
} catch (e) {
return null;
}
}

export async function getHeadersByHost(host: string) {
const ret: { [key: string]: string } = {};
for await (const [key, value] of headersDb.sublevel(host).iterator()) {
ret[key] = value;
}
return ret;
}
14 changes: 4 additions & 10 deletions src/entries/Background/handlers.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import {
getCacheByTabId,
getCookieStoreByHost,
getHeaderStoreByHost,
} from './cache';
import { getCacheByTabId } from './cache';
import { BackgroundActiontype, RequestLog } from './rpc';
import mutex from './mutex';
import browser from 'webextension-polyfill';
import { addRequest } from '../../reducers/requests';
import { urlify } from '../../utils/misc';
import { setCookies, setHeaders } from './db';

export const onSendHeaders = (
details: browser.WebRequest.OnSendHeadersDetailsType,
Expand All @@ -21,20 +18,17 @@ export const onSendHeaders = (
const { hostname } = urlify(details.url) || {};

if (hostname && details.requestHeaders) {
const headerStore = getHeaderStoreByHost(hostname);

details.requestHeaders.forEach((header) => {
const { name, value } = header;
if (/^cookie$/i.test(name) && value) {
const cookieStore = getCookieStoreByHost(hostname);
value
.split(';')
.map((v) => v.split('='))
.forEach((cookie) => {
cookieStore.set(cookie[0].trim(), cookie[1]);
setCookies(hostname, cookie[0].trim(), cookie[1]);
});
} else {
headerStore.set(name, value);
setHeaders(hostname, name, value);
}
});
}
Expand Down
Loading
Loading