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

Add plugin context to get browser storage #101

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
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
16 changes: 16 additions & 0 deletions src/components/PluginInfo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,22 @@ export function PluginPermissions({
</span>
</PermissionDescription>
)}
{pluginContent.localStorage && (
<PermissionDescription fa="fa-solid fa-database">
<span className="cursor-default">
<span className="mr-1">Access local storage storage from</span>
<MultipleParts parts={pluginContent.localStorage} />
</span>
</PermissionDescription>
)}
{pluginContent.sessionStorage && (
<PermissionDescription fa="fa-solid fa-database">
<span className="cursor-default">
<span className="mr-1">Access session storage from</span>
<MultipleParts parts={pluginContent.sessionStorage} />
</span>
</PermissionDescription>
)}
{pluginContent.requests && (
<PermissionDescription fa="fa-solid fa-globe">
<span className="cursor-default">
Expand Down
60 changes: 59 additions & 1 deletion src/entries/Background/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ const cookiesDb = db.sublevel<string, boolean>('cookies', {
const headersDb = db.sublevel<string, boolean>('headers', {
valueEncoding: 'json',
});
const localStorageDb = db.sublevel<string, any>('sessionStorage', {
valueEncoding: 'json',
});
const sessionStorageDb = db.sublevel<string, any>('localStorage', {
valueEncoding: 'json',
});
const appDb = db.sublevel<string, any>('app', {
valueEncoding: 'json',
});
Expand Down Expand Up @@ -370,7 +376,6 @@ export async function getHeaders(host: string, name: string) {
return null;
}
}

export async function getHeadersByHost(host: string) {
const ret: { [key: string]: string } = {};
for await (const [key, value] of headersDb.sublevel(host).iterator()) {
Expand All @@ -379,6 +384,59 @@ export async function getHeadersByHost(host: string) {
return ret;
}

export async function setLocalStorage(
host: string,
name: string,
value: string,
) {
return mutex.runExclusive(async () => {
await localStorageDb.sublevel(host).put(name, value);
return true;
});
}

export async function setSessionStorage(
host: string,
name: string,
value: string,
) {
return mutex.runExclusive(async () => {
await sessionStorageDb.sublevel(host).put(name, value);
return true;
});
}

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

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

export async function getLocalStorageByHost(host: string) {
const ret: { [key: string]: string } = {};
console.log('in func', host);
for await (const [key, value] of localStorageDb.sublevel(host).iterator()) {
ret[key] = value;
}
return ret;
}

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

async function getDefaultPluginsInstalled(): Promise<boolean> {
return appDb.get(AppDatabaseKey.DefaultPluginsInstalled).catch(() => false);
}
Expand Down
1 change: 0 additions & 1 deletion src/entries/Background/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ 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 Down
32 changes: 32 additions & 0 deletions src/entries/Background/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,40 @@ import { deleteCacheByTabId } from './cache';
import browser from 'webextension-polyfill';
import { getAppState, setDefaultPluginsInstalled } from './db';
import { installPlugin } from './plugins/utils';
import { BackgroundActiontype } from './rpc';
import { setLocalStorage, setSessionStorage } from './db';

(async () => {
chrome.runtime.onMessage.addListener(
async (request, sender, sendResponse) => {
if (
request.type === BackgroundActiontype.set_local_storage &&
sender.tab?.url
) {
const url = new URL(sender.tab.url);
const hostname = url.hostname;
const { localStorageData } = request;
for (const [key, value] of Object.entries(localStorageData)) {
await setLocalStorage(hostname, key, value as string);
}
}
},
);

chrome.runtime.onMessage.addListener(async (request, sender) => {
if (
request.type === BackgroundActiontype.set_session_storage &&
sender.tab?.url
) {
const url = new URL(sender.tab.url);
const hostname = url.hostname;
const { sessionStorageData } = request;
for (const [key, value] of Object.entries(sessionStorageData)) {
await setSessionStorage(hostname, key, value as string);
}
}
});

browser.webRequest.onSendHeaders.addListener(
onSendHeaders,
{
Expand Down
37 changes: 37 additions & 0 deletions src/entries/Background/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import {
getHeadersByHost,
getAppState,
setDefaultPluginsInstalled,
getSessionStorageByHost,
getLocalStorageByHost,
} from './db';
import { addOnePlugin, removeOnePlugin } from '../../reducers/plugins';
import {
Expand Down Expand Up @@ -89,6 +91,10 @@ export enum BackgroundActiontype {
get_logging_level = 'get_logging_level',
get_app_state = 'get_app_state',
set_default_plugins_installed = 'set_default_plugins_installed',
set_local_storage = 'set_local_storage',
get_local_storage = 'get_local_storage',
set_session_storage = 'set_session_storage',
get_session_storage = 'get_session_storage',
}

export type BackgroundAction = {
Expand Down Expand Up @@ -201,6 +207,14 @@ export const initRPC = () => {
case BackgroundActiontype.set_default_plugins_installed:
setDefaultPluginsInstalled(request.data).then(sendResponse);
return true;
case BackgroundActiontype.set_local_storage:
return;
case BackgroundActiontype.get_local_storage:
return;
case BackgroundActiontype.set_session_storage:
return;
case BackgroundActiontype.get_session_storage:
return;
default:
break;
}
Expand Down Expand Up @@ -464,6 +478,29 @@ function handleGetHeadersByHostname(
return true;
}

function handleGetSessionStorageByHostname(
request: BackgroundAction,
sendResponse: (data?: any) => void,
): boolean {
(async () => {
const sessionStorage = await getSessionStorageByHost(request.data);
sendResponse(sessionStorage);
})();
return true;
}

function handleGetLocalStorageByHostName(
request: BackgroundAction,
sendResponse: (data?: any) => void,
): boolean {
(async () => {
console.log('in rpc', request);
const localStorage = await getLocalStorageByHost(request.data);
sendResponse(localStorage);
})();
return true;
}

async function handleAddPlugin(
request: BackgroundAction,
sendResponse: (data?: any) => void,
Expand Down
21 changes: 20 additions & 1 deletion src/entries/Content/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import browser from 'webextension-polyfill';
import browser, { browserAction } from 'webextension-polyfill';
import { ContentScriptRequest, ContentScriptTypes, RPCServer } from './rpc';
import { BackgroundActiontype, RequestHistory } from '../Background/rpc';
import { urlify } from '../../utils/misc';
Expand All @@ -7,6 +7,25 @@ import { urlify } from '../../utils/misc';
loadScript('content.bundle.js');
const server = new RPCServer();

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === BackgroundActiontype.get_local_storage) {
console.log('in content');
chrome.runtime.sendMessage({
type: BackgroundActiontype.set_local_storage,
localStorageData: { ...localStorage },
});
}
});

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === BackgroundActiontype.get_session_storage) {
chrome.runtime.sendMessage({
type: BackgroundActiontype.set_session_storage,
sessionStorageData: { ...sessionStorage },
});
}
});

Codetrauma marked this conversation as resolved.
Show resolved Hide resolved
server.on(ContentScriptTypes.connect, async () => {
const connected = await browser.runtime.sendMessage({
type: BackgroundActiontype.connect_request,
Expand Down
67 changes: 62 additions & 5 deletions src/utils/misc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,13 @@ import browser from 'webextension-polyfill';
import NodeCache from 'node-cache';
import { getNotaryApi, getProxyApi } from './storage';
import { minimatch } from 'minimatch';
import { getCookiesByHost, getHeadersByHost } from '../entries/Background/db';

import {
getCookiesByHost,
getHeadersByHost,
getLocalStorageByHost,
getSessionStorageByHost,
setLocalStorage,
} from '../entries/Background/db';
const charwise = require('charwise');

export function urlify(
Expand Down Expand Up @@ -233,7 +238,6 @@ export const makePlugin = async (
return context.store(`${id}`);
},
};

const funcs: {
[key: string]: (callContext: CallContext, ...args: any[]) => any;
} = {};
Expand All @@ -250,6 +254,48 @@ export const makePlugin = async (
}
}

if (config?.localStorage) {
const localStorage: { [hostname: string]: { [key: string]: string } } = {};

(async () => {
const [tab] = await chrome.tabs.query({
active: true,
lastFocusedWindow: true,
});
await chrome.tabs.sendMessage(tab.id as number, {
type: BackgroundActiontype.get_local_storage,
});
})();
//@ts-ignore
for (const host of config.localStorage) {
const cache = await getLocalStorageByHost(host);
localStorage[host] = cache;
}
//@ts-ignore
injectedConfig.localStorage = JSON.stringify(localStorage);
}

if (config?.sessionStorage) {
const sessionStorage: { [hostname: string]: { [key: string]: string } } =
{};
(async () => {
const [tab] = await chrome.tabs.query({
active: true,
lastFocusedWindow: true,
});
await chrome.tabs.sendMessage(tab.id as number, {
type: BackgroundActiontype.get_session_storage,
});
})();
//@ts-ignore
for (const host of config.sessionStorage) {
const cache = await getSessionStorageByHost(host);
sessionStorage[host] = cache;
}
//@ts-ignore
injectedConfig.sessionStorage = JSON.stringify(sessionStorage);
}

if (config?.cookies) {
const cookies: { [hostname: string]: { [key: string]: string } } = {};
for (const host of config.cookies) {
Expand Down Expand Up @@ -293,12 +339,14 @@ export type StepConfig = {

export type PluginConfig = {
title: string; // The name of the plugin
description: string; // A description of the plugin's purpose
description: string; // A description of the plugin purpose
icon?: string; // A base64-encoded image string representing the plugin's icon (optional)
steps?: StepConfig[]; // An array describing the UI steps and behavior (see Step UI below) (optional)
hostFunctions?: string[]; // Host functions that the plugin will have access to
cookies?: string[]; // Cookies the plugin will have access to, cached by the extension from specified hosts (optional)
headers?: string[]; // Headers the plugin will have access to, cached by the extension from specified hosts (optional)
localStorage?: string[]; // LocalStorage the plugin will have access to, cached by the extension from specified hosts (optional)
sessionStorage?: string[]; // SessionStorage the plugin will have access to, cached by the extension from specified hosts (optional)
requests: { method: string; url: string }[]; // List of requests that the plugin is allowed to make
notaryUrls?: string[]; // List of notary services that the plugin is allowed to use (optional)
proxyUrls?: string[]; // List of websocket proxies that the plugin is allowed to use (optional)
Expand Down Expand Up @@ -348,7 +396,16 @@ export const getPluginConfig = async (
assert(typeof name === 'string' && name.length);
}
}

if (config.localStorage) {
for (const name of config.localStorage) {
assert(typeof name === 'string' && name.length);
}
}
if (config.sessionStorage) {
for (const name of config.sessionStorage) {
assert(typeof name === 'string' && name.length);
}
}
if (config.headers) {
for (const name of config.headers) {
assert(typeof name === 'string' && name.length);
Expand Down