mirror of
https://github.com/tlsnotary/tlsn-extension.git
synced 2026-01-10 05:28:02 -05:00
Compare commits
3 Commits
requestbui
...
0.1.0.700
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d47cf0d8ea | ||
|
|
25f35d0051 | ||
|
|
5ccdd9b06a |
6180
package-lock.json
generated
6180
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tlsn-extension",
|
||||
"version": "0.1.0.6",
|
||||
"version": "0.1.0.700",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -38,8 +38,8 @@
|
||||
"redux-logger": "^3.0.6",
|
||||
"redux-thunk": "^2.4.2",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"tlsn-js": "0.1.0-alpha.6.2",
|
||||
"tlsn-jsV5.3": "npm:tlsn-js@0.1.0-alpha.5.3"
|
||||
"tlsn-js": "0.1.0-alpha.7.1",
|
||||
"tlsn-js-v5": "npm:tlsn-js@0.1.0-alpha.5.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.12",
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
You can find example plugins at https://github.com/tlsnotary/tlsn-plugin-boilerplate/tree/main/examples
|
||||
24
pnpm-lock.yaml
generated
24
pnpm-lock.yaml
generated
@@ -72,11 +72,11 @@ dependencies:
|
||||
specifier: ^3.3.3
|
||||
version: 3.4.3
|
||||
tlsn-js:
|
||||
specifier: 0.1.0-alpha.6.2
|
||||
version: 0.1.0-alpha.6.2
|
||||
tlsn-jsV5.3:
|
||||
specifier: npm:tlsn-js@0.1.0-alpha.5.3
|
||||
version: /tlsn-js@0.1.0-alpha.5.3
|
||||
specifier: 0.1.0-alpha.7.1
|
||||
version: 0.1.0-alpha.7.1
|
||||
tlsn-js-v5:
|
||||
specifier: npm:tlsn-js@0.1.0-alpha.5.4
|
||||
version: /tlsn-js@0.1.0-alpha.5.4
|
||||
|
||||
devDependencies:
|
||||
'@babel/core':
|
||||
@@ -7974,16 +7974,22 @@ packages:
|
||||
resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==}
|
||||
dev: true
|
||||
|
||||
/tlsn-js@0.1.0-alpha.5.3:
|
||||
resolution: {integrity: sha512-eTSCQ6MaH8mN2oCfLsQDe/mdfTlIq74MbKVesV6M01C2SRE0FJcVlTWMsnT3L+wOpvOlvsiBeCWV7T9m/YMzew==}
|
||||
/tlsn-js@0.1.0-alpha.5.4:
|
||||
resolution: {integrity: sha512-qbqaDjApXarohn/XMJrxMsNHYTCzy+pw0Fc8gtPPN17PLE+1DwwLTXAAhnxYqYQyo3+Hmy+ODd4C02+KCwRWmg==}
|
||||
engines: {node: '>= 16.20.2'}
|
||||
dependencies:
|
||||
comlink: 4.4.1
|
||||
dev: false
|
||||
|
||||
/tlsn-js@0.1.0-alpha.6.2:
|
||||
resolution: {integrity: sha512-6PANWQEFw48VFNfDgA017zcNRae2OutzNmE5Xcc/h6lwkZZ8MBZIFAFfz/WHZJ3fcFJumaKrG80gpomP6blZqw==}
|
||||
/tlsn-js@0.1.0-alpha.7.1:
|
||||
resolution: {integrity: sha512-EWdRp1VQBfdre8jehJgmDjtDvt01ZL1JWbcscctnFTLIIwMYS7IBxU07UYG0NMZFXeTE8PlrUDEVwEl1+vla+g==}
|
||||
engines: {node: '>= 16.20.2'}
|
||||
dependencies:
|
||||
tlsn-wasm: 0.1.0-alpha.7.2
|
||||
dev: false
|
||||
|
||||
/tlsn-wasm@0.1.0-alpha.7.2:
|
||||
resolution: {integrity: sha512-NzrDfOxmFtMHDb4lmMsx6RaS6F+IVXEHxK0zow8jpnx+NryuJ+qnp4380Lq0uj61w/Yuq+yzOhzFe6Bpeo59dA==}
|
||||
dev: false
|
||||
|
||||
/tmp@0.0.33:
|
||||
|
||||
BIN
src/assets/plugins/discord_dm.wasm
Normal file
BIN
src/assets/plugins/discord_dm.wasm
Normal file
Binary file not shown.
BIN
src/assets/plugins/twitter_profile.wasm
Normal file
BIN
src/assets/plugins/twitter_profile.wasm
Normal file
Binary file not shown.
@@ -24,6 +24,7 @@ import {
|
||||
} from '../../utils/plugins';
|
||||
import { ErrorModal } from '../ErrorModal';
|
||||
import classNames from 'classnames';
|
||||
import DefaultPluginIcon from '../../assets/img/default-plugin-icon.png';
|
||||
|
||||
export default function PluginUploadInfo(): ReactElement {
|
||||
const [error, showError] = useState('');
|
||||
@@ -122,7 +123,7 @@ export function PluginInfoModal(props: {
|
||||
<ModalHeader className="w-full p-2 border-gray-200 text-gray-500">
|
||||
{header || (
|
||||
<div className="flex flex-row items-end justify-start gap-2">
|
||||
<img className="h-5" src={logo} alt="logo" />
|
||||
<img className="h-5" src={logo || DefaultPluginIcon} alt="logo" />
|
||||
<span className="font-semibold">{`Installing ${pluginContent.title}`}</span>
|
||||
</div>
|
||||
)}
|
||||
@@ -132,7 +133,7 @@ export function PluginInfoModal(props: {
|
||||
<>
|
||||
<img
|
||||
className="w-12 h-12"
|
||||
src={pluginContent.icon}
|
||||
src={pluginContent.icon || DefaultPluginIcon}
|
||||
alt="Plugin Icon"
|
||||
/>
|
||||
<span className="text-3xl text-center">
|
||||
|
||||
@@ -169,7 +169,7 @@ export function Plugin(props: {
|
||||
<PluginInfoModalContent className="flex flex-col items-center cursor-default">
|
||||
<img
|
||||
className="w-12 h-12 mb-2"
|
||||
src={config.icon}
|
||||
src={config.icon || DefaultPluginIcon}
|
||||
alt="Plugin Icon"
|
||||
/>
|
||||
<span className="text-3xl text-blue-600 font-semibold">
|
||||
|
||||
@@ -28,6 +28,12 @@ const cookiesDb = db.sublevel<string, boolean>('cookies', {
|
||||
const headersDb = db.sublevel<string, boolean>('headers', {
|
||||
valueEncoding: 'json',
|
||||
});
|
||||
const appDb = db.sublevel<string, any>('app', {
|
||||
valueEncoding: 'json',
|
||||
});
|
||||
enum AppDatabaseKey {
|
||||
DefaultPluginsInstalled = 'DefaultPluginsInstalled',
|
||||
}
|
||||
|
||||
export async function addNotaryRequest(
|
||||
now = Date.now(),
|
||||
@@ -372,3 +378,19 @@ export async function getHeadersByHost(host: string) {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
async function getDefaultPluginsInstalled(): Promise<boolean> {
|
||||
return appDb.get(AppDatabaseKey.DefaultPluginsInstalled).catch(() => false);
|
||||
}
|
||||
|
||||
export async function setDefaultPluginsInstalled(installed = false) {
|
||||
return mutex.runExclusive(async () => {
|
||||
await appDb.put(AppDatabaseKey.DefaultPluginsInstalled, installed);
|
||||
});
|
||||
}
|
||||
|
||||
export async function getAppState() {
|
||||
return {
|
||||
defaultPluginsInstalled: await getDefaultPluginsInstalled(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { onBeforeRequest, onResponseStarted, onSendHeaders } from './handlers';
|
||||
import { deleteCacheByTabId } from './cache';
|
||||
import browser from 'webextension-polyfill';
|
||||
import { getAppState, setDefaultPluginsInstalled } from './db';
|
||||
import { installPlugin } from './plugins/utils';
|
||||
|
||||
(async () => {
|
||||
browser.webRequest.onSendHeaders.addListener(
|
||||
@@ -31,6 +33,19 @@ import browser from 'webextension-polyfill';
|
||||
deleteCacheByTabId(tabId);
|
||||
});
|
||||
|
||||
const { defaultPluginsInstalled } = await getAppState();
|
||||
|
||||
if (!defaultPluginsInstalled) {
|
||||
try {
|
||||
const twitterProfileUrl = browser.runtime.getURL('twitter_profile.wasm');
|
||||
const discordDmUrl = browser.runtime.getURL('discord_dm.wasm');
|
||||
await installPlugin(twitterProfileUrl);
|
||||
await installPlugin(discordDmUrl);
|
||||
} finally {
|
||||
await setDefaultPluginsInstalled(true);
|
||||
}
|
||||
}
|
||||
|
||||
const { initRPC } = await import('./rpc');
|
||||
await createOffscreenDocument();
|
||||
initRPC();
|
||||
|
||||
29
src/entries/Background/plugins/utils.ts
Normal file
29
src/entries/Background/plugins/utils.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { addPlugin, addPluginConfig, addPluginMetadata } from '../db';
|
||||
import { getPluginConfig } from '../../../utils/misc';
|
||||
|
||||
export async function installPlugin(
|
||||
urlOrBuffer: ArrayBuffer | string,
|
||||
origin = '',
|
||||
filePath = '',
|
||||
metadata: {[key: string]: string} = {},
|
||||
) {
|
||||
let arrayBuffer;
|
||||
|
||||
if (typeof urlOrBuffer === 'string') {
|
||||
const resp = await fetch(urlOrBuffer);
|
||||
arrayBuffer = await resp.arrayBuffer();
|
||||
} else {
|
||||
arrayBuffer = urlOrBuffer;
|
||||
}
|
||||
|
||||
const config = await getPluginConfig(arrayBuffer);
|
||||
const hex = Buffer.from(arrayBuffer).toString('hex');
|
||||
const hash = await addPlugin(hex);
|
||||
await addPluginConfig(hash!, config);
|
||||
await addPluginMetadata(hash!, {
|
||||
...metadata,
|
||||
origin,
|
||||
filePath,
|
||||
});
|
||||
return hash;
|
||||
}
|
||||
@@ -24,6 +24,8 @@ import {
|
||||
getPlugins,
|
||||
getCookiesByHost,
|
||||
getHeadersByHost,
|
||||
getAppState,
|
||||
setDefaultPluginsInstalled,
|
||||
} from './db';
|
||||
import { addOnePlugin, removeOnePlugin } from '../../reducers/plugins';
|
||||
import {
|
||||
@@ -85,6 +87,8 @@ export enum BackgroundActiontype {
|
||||
run_plugin_request = 'run_plugin_request',
|
||||
run_plugin_response = 'run_plugin_response',
|
||||
get_logging_level = 'get_logging_level',
|
||||
get_app_state = 'get_app_state',
|
||||
set_default_plugins_installed = 'set_default_plugins_installed',
|
||||
}
|
||||
|
||||
export type BackgroundAction = {
|
||||
@@ -192,6 +196,12 @@ export const initRPC = () => {
|
||||
case BackgroundActiontype.get_logging_level:
|
||||
getLoggingFilter().then(sendResponse);
|
||||
return true;
|
||||
case BackgroundActiontype.get_app_state:
|
||||
getAppState().then(sendResponse);
|
||||
return true;
|
||||
case BackgroundActiontype.set_default_plugins_installed:
|
||||
setDefaultPluginsInstalled(request.data).then(sendResponse);
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ContentScriptTypes, RPCClient } from './rpc';
|
||||
import { RequestHistory } from '../Background/rpc';
|
||||
import { PluginConfig, PluginMetadata } from '../../utils/misc';
|
||||
import { Proof } from '../../utils/types';
|
||||
import { PresentationJSON } from '../../utils/types';
|
||||
|
||||
const client = new RPCClient();
|
||||
|
||||
@@ -27,7 +27,7 @@ class TLSN {
|
||||
return resp || [];
|
||||
}
|
||||
|
||||
async getProof(id: string): Promise<Proof | null> {
|
||||
async getProof(id: string): Promise<PresentationJSON | null> {
|
||||
const resp = await client.call(ContentScriptTypes.get_proof, {
|
||||
id,
|
||||
});
|
||||
@@ -52,7 +52,7 @@ class TLSN {
|
||||
[k: string]: string;
|
||||
};
|
||||
},
|
||||
): Promise<Proof> {
|
||||
): Promise<PresentationJSON> {
|
||||
const resp = await client.call(ContentScriptTypes.notarize, {
|
||||
url,
|
||||
method: requestOptions?.method,
|
||||
|
||||
@@ -3,19 +3,20 @@ import * as Comlink from 'comlink';
|
||||
import { OffscreenActionTypes } from './types';
|
||||
import {
|
||||
NotaryServer,
|
||||
Prover as _Prover,
|
||||
NotarizedSession as _NotarizedSession,
|
||||
TlsProof as _TlsProof,
|
||||
Prover as TProver,
|
||||
Presentation as TPresentation,
|
||||
Transcript,
|
||||
} from 'tlsn-js';
|
||||
import { verify } from 'tlsn-jsV5.3';
|
||||
import { verify } from 'tlsn-js-v5';
|
||||
|
||||
import { urlify } from '../../utils/misc';
|
||||
import { BackgroundActiontype } from '../Background/rpc';
|
||||
import browser from 'webextension-polyfill';
|
||||
import { Proof, ProofV1 } from '../../utils/types';
|
||||
import { PresentationJSON } from '../../utils/types';
|
||||
import { PresentationJSON as PresentationJSONa7 } from 'tlsn-js/build/types';
|
||||
import { Method } from 'tlsn-js/wasm/pkg';
|
||||
|
||||
const { init, Prover, NotarizedSession, TlsProof }: any = Comlink.wrap(
|
||||
const { init, Prover, Presentation }: any = Comlink.wrap(
|
||||
new Worker(new URL('./worker.ts', import.meta.url)),
|
||||
);
|
||||
|
||||
@@ -111,7 +112,7 @@ const Offscreen = () => {
|
||||
}
|
||||
case BackgroundActiontype.verify_prove_request: {
|
||||
(async () => {
|
||||
const proof: Proof = request.data.proof;
|
||||
const proof: PresentationJSON = request.data.proof;
|
||||
const result: { sent: string; recv: string } =
|
||||
await verifyProof(proof);
|
||||
|
||||
@@ -194,7 +195,7 @@ async function createProof(options: {
|
||||
id: string;
|
||||
secretHeaders: string[];
|
||||
secretResps: string[];
|
||||
}): Promise<ProofV1> {
|
||||
}): Promise<PresentationJSONa7> {
|
||||
const {
|
||||
url,
|
||||
method = 'GET',
|
||||
@@ -211,7 +212,7 @@ async function createProof(options: {
|
||||
|
||||
const hostname = urlify(url)?.hostname || '';
|
||||
const notary = NotaryServer.from(notaryUrl);
|
||||
const prover: _Prover = await new Prover({
|
||||
const prover: TProver = await new Prover({
|
||||
id,
|
||||
serverDns: hostname,
|
||||
maxSentData,
|
||||
@@ -260,24 +261,21 @@ async function createProof(options: {
|
||||
),
|
||||
};
|
||||
|
||||
const session: _NotarizedSession = await new NotarizedSession(
|
||||
await prover.notarize(commit),
|
||||
);
|
||||
const notarizationOutputs = await prover.notarize(commit);
|
||||
|
||||
const proofHex = await session.proof(commit);
|
||||
const proof: ProofV1 = {
|
||||
version: '1.0',
|
||||
meta: {
|
||||
notaryUrl,
|
||||
websocketProxyUrl,
|
||||
},
|
||||
data: proofHex,
|
||||
};
|
||||
return proof;
|
||||
const presentation = (await new Presentation({
|
||||
attestationHex: notarizationOutputs.attestation,
|
||||
secretsHex: notarizationOutputs.secrets,
|
||||
notaryUrl: notarizationOutputs.notaryUrl,
|
||||
websocketProxyUrl: notarizationOutputs.websocketProxyUrl,
|
||||
reveal: commit,
|
||||
})) as TPresentation;
|
||||
const presentationJSON = await presentation.json();
|
||||
return presentationJSON;
|
||||
}
|
||||
|
||||
async function verifyProof(
|
||||
proof: Proof,
|
||||
proof: PresentationJSON,
|
||||
): Promise<{ sent: string; recv: string }> {
|
||||
let result: { sent: string; recv: string };
|
||||
|
||||
@@ -286,12 +284,17 @@ async function verifyProof(
|
||||
result = await verify(proof);
|
||||
break;
|
||||
}
|
||||
case '1.0': {
|
||||
const tlsProof: _TlsProof = await new TlsProof(proof.data);
|
||||
result = await tlsProof.verify({
|
||||
typ: 'P256',
|
||||
key: await NotaryServer.from(proof.meta.notaryUrl).publicKey(),
|
||||
case '0.1.0-alpha.7': {
|
||||
const presentation: TPresentation = await new Presentation(proof.data);
|
||||
const verifierOutput = await presentation.verify();
|
||||
const transcript = new Transcript({
|
||||
sent: verifierOutput.transcript.sent,
|
||||
recv: verifierOutput.transcript.recv,
|
||||
});
|
||||
result = {
|
||||
sent: transcript.sent(),
|
||||
recv: transcript.recv(),
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import * as Comlink from 'comlink';
|
||||
import init, { Prover, NotarizedSession, TlsProof } from 'tlsn-js';
|
||||
import init, { Prover, Presentation } from 'tlsn-js';
|
||||
|
||||
Comlink.expose({
|
||||
init,
|
||||
Prover,
|
||||
NotarizedSession,
|
||||
TlsProof,
|
||||
Presentation,
|
||||
});
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
],
|
||||
"web_accessible_resources": [
|
||||
{
|
||||
"resources": ["content.styles.css", "icon-128.png", "icon-34.png", "content.bundle.js"],
|
||||
"resources": ["content.styles.css", "icon-128.png", "icon-34.png", "content.bundle.js", "discord_dm.wasm", "twitter_profile.wasm"],
|
||||
"matches": ["http://*/*", "https://*/*", "<all_urls>"]
|
||||
}
|
||||
],
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
InputBody,
|
||||
FormBodyTable,
|
||||
parseResponse,
|
||||
} from '../../utils/requestbuilder';
|
||||
} from '../../components/RequestBuilder';
|
||||
|
||||
enum TabType {
|
||||
Params = 'Params',
|
||||
|
||||
@@ -26,7 +26,7 @@ export async function getMaxRecv() {
|
||||
}
|
||||
|
||||
export async function getNotaryApi() {
|
||||
return await get(NOTARY_API_LS_KEY, 'https://notary.pse.dev/v0.1.0-alpha.6');
|
||||
return await get(NOTARY_API_LS_KEY, 'https://notary.pse.dev/v0.1.0-alpha.7');
|
||||
}
|
||||
|
||||
export async function getProxyApi() {
|
||||
|
||||
@@ -1,18 +1,10 @@
|
||||
export type Proof = ProofV0 | ProofV1;
|
||||
import { PresentationJSON as PresentationJSONa7 } from 'tlsn-js/build/types';
|
||||
|
||||
export type ProofV0 = {
|
||||
export type PresentationJSON = PresentationJSONa5 | PresentationJSONa7;
|
||||
|
||||
export type PresentationJSONa5 = {
|
||||
version?: undefined;
|
||||
session: any;
|
||||
substrings: any;
|
||||
notaryUrl: string;
|
||||
};
|
||||
|
||||
export type ProofV1 = {
|
||||
version: '1.0';
|
||||
data: string;
|
||||
meta: {
|
||||
notaryUrl: string;
|
||||
websocketProxyUrl: string;
|
||||
pluginUrl?: string;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -40,7 +40,8 @@ var options = {
|
||||
mode: process.env.NODE_ENV || "development",
|
||||
ignoreWarnings: [
|
||||
/Circular dependency between chunks with runtime/,
|
||||
/ResizeObserver loop completed with undelivered notifications/
|
||||
/ResizeObserver loop completed with undelivered notifications/,
|
||||
/Should not import the named export/,
|
||||
],
|
||||
|
||||
entry: {
|
||||
@@ -82,6 +83,9 @@ var options = {
|
||||
loader: "sass-loader",
|
||||
options: {
|
||||
sourceMap: true,
|
||||
sassOptions: {
|
||||
silenceDeprecations: ["legacy-js-api"],
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -199,31 +203,21 @@ var options = {
|
||||
}),
|
||||
new CopyWebpackPlugin({
|
||||
patterns: [
|
||||
// {
|
||||
// from: "node_modules/tlsn-js/build/7.js",
|
||||
// to: path.join(__dirname, "build"),
|
||||
// force: true,
|
||||
// },
|
||||
// {
|
||||
// from: "node_modules/tlsn-js/build/250.js",
|
||||
// to: path.join(__dirname, "build"),
|
||||
// force: true,
|
||||
// },
|
||||
// {
|
||||
// from: "node_modules/tlsn-js/build/278.js",
|
||||
// to: path.join(__dirname, "build"),
|
||||
// force: true,
|
||||
// },
|
||||
// {
|
||||
// from: "node_modules/tlsn-js/build/349.js",
|
||||
// to: path.join(__dirname, "build"),
|
||||
// force: true,
|
||||
// },
|
||||
{
|
||||
from: "node_modules/tlsn-js/build",
|
||||
to: path.join(__dirname, "build"),
|
||||
force: true,
|
||||
},
|
||||
{
|
||||
from: "src/assets/plugins/discord_dm.wasm",
|
||||
to: path.join(__dirname, "build"),
|
||||
force: true,
|
||||
},
|
||||
{
|
||||
from: "src/assets/plugins/twitter_profile.wasm",
|
||||
to: path.join(__dirname, "build"),
|
||||
force: true,
|
||||
},
|
||||
],
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
|
||||
Reference in New Issue
Block a user