mirror of
https://github.com/tlsnotary/tlsn-extension.git
synced 2026-01-09 21:18:02 -05:00
minor refactoring and bugfixes (#22)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
{
|
||||
root: true,
|
||||
"root": true,
|
||||
"extends": ["prettier", "plugin:@typescript-eslint/recommended"],
|
||||
"plugins": ["prettier", "@typescript-eslint"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
@@ -7,6 +7,7 @@
|
||||
"prettier/prettier": "error",
|
||||
"@typescript-eslint/no-explicit-any": 1,
|
||||
"@typescript-eslint/no-var-requires": 0,
|
||||
"@typescript-eslint/ban-ts-comment": 0,
|
||||
"no-undef": "error",
|
||||
"padding-line-between-statements": "error"
|
||||
},
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"clone:tlsn": "bash ./utils/download-tlsn.sh",
|
||||
"build:wasm": "wasm-pack build --target web wasm/prover",
|
||||
"build": "NODE_ENV=production node utils/build.js",
|
||||
"build:webpack": "NODE_ENV=production webpack --config webpack.config.js",
|
||||
"dev": "NODE_ENV=development node utils/webserver.js",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix"
|
||||
|
||||
@@ -68,9 +68,7 @@ function OneRequestHistory(props: { requestId: string }): ReactElement {
|
||||
</div>
|
||||
<div className="flex flex-row">
|
||||
<div className="font-bold text-slate-400">Host:</div>
|
||||
<div className="ml-2 text-slate-800">
|
||||
{requestUrl?.host}
|
||||
</div>
|
||||
<div className="ml-2 text-slate-800">{requestUrl?.host}</div>
|
||||
</div>
|
||||
<div className="flex flex-row">
|
||||
<div className="font-bold text-slate-400">Notary API:</div>
|
||||
@@ -95,7 +93,9 @@ function OneRequestHistory(props: { requestId: string }): ReactElement {
|
||||
</div>
|
||||
<div
|
||||
className="flex flex-row flex-grow-0 gap-2 self-end items-center justify-end px-2 py-1 bg-slate-100 text-slate-300 hover:bg-slate-200 hover:text-slate-500 hover:font-bold"
|
||||
onClick={() => download(`${request?.id}.json`, JSON.stringify(request?.proof))}
|
||||
onClick={() =>
|
||||
download(`${request?.id}.json`, JSON.stringify(request?.proof))
|
||||
}
|
||||
>
|
||||
<Icon className="" fa="fa-solid fa-download" size={1} />
|
||||
<span className="text-xs font-bold">Download</span>
|
||||
|
||||
@@ -8,8 +8,6 @@ export default function Notarize(): ReactElement {
|
||||
const request = useRequestHistory(params.requestId);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col flex-nowrap flex-grow">
|
||||
{request?.id}
|
||||
</div>
|
||||
<div className="flex flex-col flex-nowrap flex-grow">{request?.id}</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
} from '../../utils/storage';
|
||||
|
||||
export default function Options(): ReactElement {
|
||||
const [notary, setNotary] = useState('http://localhost:7047');
|
||||
const [notary, setNotary] = useState('https://localhost:7047');
|
||||
const [proxy, setProxy] = useState('ws://127.0.0.1:55688');
|
||||
const [dirty, setDirty] = useState(false);
|
||||
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
import React, { ReactNode, ReactElement, useState } from 'react';
|
||||
import React, {
|
||||
ReactNode,
|
||||
ReactElement,
|
||||
useState,
|
||||
MouseEventHandler,
|
||||
} from 'react';
|
||||
import { useParams, useLocation, useNavigate } from 'react-router';
|
||||
import c from 'classnames';
|
||||
import { useRequestHistory } from '../../reducers/history';
|
||||
import RequestBuilder from '../../pages/RequestBuilder';
|
||||
import Icon from '../../components/Icon';
|
||||
import { download } from '../../utils/misc';
|
||||
|
||||
export default function ProofViewer(): ReactElement {
|
||||
const {requestId} = useParams<{ requestId: string }>();
|
||||
const { requestId } = useParams<{ requestId: string }>();
|
||||
const request = useRequestHistory(requestId);
|
||||
const navigate = useNavigate();
|
||||
const [ tab, setTab ] = useState('sent');
|
||||
const loc = useLocation();
|
||||
|
||||
const [tab, setTab] = useState('sent');
|
||||
|
||||
return (
|
||||
<div className="flex flex-col w-full py-2 gap-2 flex-grow">
|
||||
<div className="flex flex-col px-2">
|
||||
@@ -25,22 +28,19 @@ export default function ProofViewer(): ReactElement {
|
||||
onClick={() => navigate(-1)}
|
||||
fa="fa-solid fa-xmark"
|
||||
/>
|
||||
<TabLabel
|
||||
onClick={() => setTab('sent')}
|
||||
active={tab === 'sent'}
|
||||
>
|
||||
<TabLabel onClick={() => setTab('sent')} active={tab === 'sent'}>
|
||||
Sent
|
||||
</TabLabel>
|
||||
<TabLabel
|
||||
onClick={() => setTab('recv')}
|
||||
active={tab === 'recv'}
|
||||
>
|
||||
<TabLabel onClick={() => setTab('recv')} active={tab === 'recv'}>
|
||||
Recv
|
||||
</TabLabel>
|
||||
<div className="flex flex-row flex-grow items-center justify-end">
|
||||
<button
|
||||
<button
|
||||
className="button"
|
||||
onClick={() => download(request.id, JSON.stringify(request.proof))}
|
||||
onClick={() => {
|
||||
if (!request) return;
|
||||
download(request.id, JSON.stringify(request.proof));
|
||||
}}
|
||||
>
|
||||
Download
|
||||
</button>
|
||||
@@ -51,19 +51,19 @@ export default function ProofViewer(): ReactElement {
|
||||
{tab === 'sent' && (
|
||||
<textarea
|
||||
className="w-full resize-none bg-slate-100 text-slate-800 border p-2 text-[10px] break-all h-full outline-none font-mono"
|
||||
value={request.verification?.sent}
|
||||
value={request?.verification?.sent}
|
||||
></textarea>
|
||||
)}
|
||||
{tab === 'recv' && (
|
||||
<textarea
|
||||
className="w-full resize-none bg-slate-100 text-slate-800 border p-2 text-[10px] break-all h-full outline-none font-mono"
|
||||
value={request.verification?.recv}
|
||||
value={request?.verification?.recv}
|
||||
></textarea>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
function TabLabel(props: {
|
||||
children: ReactNode;
|
||||
@@ -74,7 +74,8 @@ function TabLabel(props: {
|
||||
<button
|
||||
className={c('px-1 select-none cursor-pointer font-bold', {
|
||||
'text-slate-800 border-b-2 border-green-500': props.active,
|
||||
'text-slate-400 border-b-2 border-transparent hover:text-slate-500': !props.active,
|
||||
'text-slate-400 border-b-2 border-transparent hover:text-slate-500':
|
||||
!props.active,
|
||||
})}
|
||||
onClick={props.onClick}
|
||||
>
|
||||
|
||||
@@ -5,18 +5,10 @@ import React, {
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react';
|
||||
import {
|
||||
BackgroundActiontype,
|
||||
RequestLog,
|
||||
} from '../../pages/Background/actionTypes';
|
||||
import {
|
||||
notarizeRequest,
|
||||
useRequest,
|
||||
} from '../../reducers/requests';
|
||||
import { notarizeRequest, useRequest } from '../../reducers/requests';
|
||||
import classNames from 'classnames';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import {
|
||||
Navigate,
|
||||
Route,
|
||||
Routes,
|
||||
useLocation,
|
||||
@@ -34,44 +26,44 @@ type Props = {
|
||||
|
||||
const maxTranscriptSize = 16384;
|
||||
|
||||
const authToken = 'a28cae3969369c26c1410f5bded83c3f4f914fbc';
|
||||
const accessToken =
|
||||
'AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA';
|
||||
const csrfToken =
|
||||
'b73b3488687683372af2ea77486a444ccaa5327bbabad709df1b5161a6b83c8d7ec19106a82cb8dd5f8569632ee95ab4c6dc2abf5ad2ed7fa11b8340fcbe86a8fc00df28db6c4109a807f7cb12dd19da';
|
||||
const userAgent =
|
||||
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36';
|
||||
|
||||
|
||||
export default function RequestDetail(props: Props): ReactElement {
|
||||
const request = useRequest(props.requestId);
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const notarize = useCallback(async () => {
|
||||
if (!request) return;
|
||||
|
||||
const hostname = urlify(request.url)?.hostname;
|
||||
const notaryUrl = await get(NOTARY_API_LS_KEY);
|
||||
const websocketProxyUrl = await get(PROXY_API_LS_KEY);
|
||||
const headers = request
|
||||
.requestHeaders.reduce((acc, h) => {
|
||||
if (!(/^(origin|referer|Accept-Language|Accept-EncodingAccept)$|^(sec-|x-twitter-)/i.test(h.name))) {
|
||||
acc[h.name] = h.value;
|
||||
}
|
||||
return acc;
|
||||
}, { Host: urlify(request.url)?.hostname });
|
||||
|
||||
//TODO: for some reason, these needs to be override for twitter to work
|
||||
headers['Accept-Encoding'] = 'identity';
|
||||
headers['Connection'] = 'close';
|
||||
const headers: { [k: string]: string } = request.requestHeaders.reduce(
|
||||
(acc: any, h) => {
|
||||
acc[h.name] = h.value;
|
||||
return acc;
|
||||
},
|
||||
{ Host: hostname },
|
||||
);
|
||||
|
||||
dispatch(notarizeRequest({
|
||||
url: request.url,
|
||||
method: request.method,
|
||||
headers,
|
||||
body: request.body,
|
||||
maxTranscriptSize,
|
||||
notaryUrl,
|
||||
websocketProxyUrl,
|
||||
}))
|
||||
//TODO: for some reason, these needs to be override for twitter api to work
|
||||
if (hostname === 'api.twitter.com') {
|
||||
headers['Accept-Encoding'] = 'identity';
|
||||
headers['Connection'] = 'close';
|
||||
}
|
||||
|
||||
dispatch(
|
||||
// @ts-ignore
|
||||
notarizeRequest({
|
||||
url: request.url,
|
||||
method: request.method,
|
||||
headers,
|
||||
body: request.requestBody,
|
||||
maxTranscriptSize,
|
||||
notaryUrl,
|
||||
websocketProxyUrl,
|
||||
}),
|
||||
);
|
||||
navigate(`/history`);
|
||||
}, [request]);
|
||||
|
||||
@@ -102,9 +94,18 @@ export default function RequestDetail(props: Props): ReactElement {
|
||||
</button>
|
||||
</div>
|
||||
<Routes>
|
||||
<Route path="headers" element={<RequestHeaders requestId={props.requestId} />} />
|
||||
<Route path="payloads" element={<RequestPayload requestId={props.requestId} />} />
|
||||
<Route path="response" element={<WebResponse requestId={props.requestId} />} />
|
||||
<Route
|
||||
path="headers"
|
||||
element={<RequestHeaders requestId={props.requestId} />}
|
||||
/>
|
||||
<Route
|
||||
path="payloads"
|
||||
element={<RequestPayload requestId={props.requestId} />}
|
||||
/>
|
||||
<Route
|
||||
path="response"
|
||||
element={<WebResponse requestId={props.requestId} />}
|
||||
/>
|
||||
<Route path="/" element={<NavigateWithParams to="/headers" />} />
|
||||
</Routes>
|
||||
</>
|
||||
|
||||
@@ -38,8 +38,8 @@ export type RequestHistory = {
|
||||
url: string;
|
||||
method: string;
|
||||
headers: { [key: string]: string };
|
||||
body: string;
|
||||
maxTranscriptSize: string;
|
||||
body?: string;
|
||||
maxTranscriptSize: number;
|
||||
notaryUrl: string;
|
||||
websocketProxyUrl: string;
|
||||
status: '' | 'pending' | 'success' | 'error';
|
||||
|
||||
@@ -9,7 +9,7 @@ import NodeCache from 'node-cache';
|
||||
import { addRequest } from '../../reducers/requests';
|
||||
import { addRequestHistory } from '../../reducers/history';
|
||||
import { Level } from 'level';
|
||||
import charwise from 'charwise';
|
||||
const charwise = require('charwise');
|
||||
|
||||
let RequestsLogs: {
|
||||
[tabId: string]: NodeCache;
|
||||
@@ -38,6 +38,7 @@ chrome.tabs.onRemoved.addListener((tab) => {
|
||||
|
||||
(async () => {
|
||||
const offscreenUrl = chrome.runtime.getURL('offscreen.html');
|
||||
// @ts-ignore
|
||||
const existingContexts = await chrome.runtime.getContexts({
|
||||
contextTypes: ['OFFSCREEN_DOCUMENT'],
|
||||
documentUrls: [offscreenUrl],
|
||||
@@ -224,7 +225,7 @@ chrome.tabs.onRemoved.addListener((tab) => {
|
||||
if (error) {
|
||||
const newReq = await setNotaryRequestError(id, error);
|
||||
if (!newReq) return;
|
||||
|
||||
|
||||
chrome.runtime.sendMessage({
|
||||
type: BackgroundActiontype.push_action,
|
||||
data: {
|
||||
@@ -237,7 +238,7 @@ chrome.tabs.onRemoved.addListener((tab) => {
|
||||
if (verification) {
|
||||
const newReq = await setNotaryRequestVerification(id, verification);
|
||||
if (!newReq) return;
|
||||
|
||||
|
||||
chrome.runtime.sendMessage({
|
||||
type: BackgroundActiontype.push_action,
|
||||
data: {
|
||||
@@ -329,16 +330,19 @@ chrome.tabs.onRemoved.addListener((tab) => {
|
||||
const db = new Level('./ext-db', {
|
||||
valueEncoding: 'json',
|
||||
});
|
||||
const historyDb = db.sublevel('history', { valueEncoding: 'json' });
|
||||
const historyDb = db.sublevel<string, RequestHistory>('history', {
|
||||
valueEncoding: 'json',
|
||||
});
|
||||
|
||||
async function addNotaryRequest(
|
||||
now = Date.now(),
|
||||
request: RequestHistory,
|
||||
request: Omit<RequestHistory, 'status' | 'id'>,
|
||||
): Promise<RequestHistory> {
|
||||
const id = charwise.encode(now).toString('hex');
|
||||
const newReq = {
|
||||
const newReq: RequestHistory = {
|
||||
...request,
|
||||
id,
|
||||
status: '',
|
||||
};
|
||||
await historyDb.put(id, newReq);
|
||||
return newReq;
|
||||
@@ -352,7 +356,7 @@ async function addNotaryRequestProofs(
|
||||
|
||||
if (!existing) return null;
|
||||
|
||||
const newReq = {
|
||||
const newReq: RequestHistory = {
|
||||
...existing,
|
||||
proof,
|
||||
status: 'success',
|
||||
@@ -389,7 +393,7 @@ async function setNotaryRequestError(
|
||||
|
||||
if (!existing) return null;
|
||||
|
||||
const newReq = {
|
||||
const newReq: RequestHistory = {
|
||||
...existing,
|
||||
error,
|
||||
status: 'error',
|
||||
|
||||
@@ -49,13 +49,13 @@ class TLSN {
|
||||
await this.waitForStart();
|
||||
console.log('worker', url, {
|
||||
...options,
|
||||
notaryUrl: options.notaryUrl,
|
||||
websocketProxyUrl: options.websocketProxyUrl,
|
||||
notaryUrl: options?.notaryUrl,
|
||||
websocketProxyUrl: options?.websocketProxyUrl,
|
||||
});
|
||||
const resProver = await prover(url, {
|
||||
...options,
|
||||
notaryUrl: options.notaryUrl,
|
||||
websocketProxyUrl: options.websocketProxyUrl,
|
||||
notaryUrl: options?.notaryUrl,
|
||||
websocketProxyUrl: options?.websocketProxyUrl,
|
||||
});
|
||||
const resJSON = JSON.parse(resProver);
|
||||
devlog('!@# resProver,resJSON=', { resProver, resJSON });
|
||||
|
||||
@@ -30,18 +30,18 @@ export default function RequestBuilder(props?: {
|
||||
const loc = useLocation();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const subpath = props.subpath || '/custom';
|
||||
const [_url, setUrl] = useState(props.url || '');
|
||||
const subpath = props?.subpath || '/custom';
|
||||
const [_url, setUrl] = useState(props?.url || '');
|
||||
const [params, setParams] = useState<[string, string, boolean?][]>(
|
||||
props.params || [],
|
||||
props?.params || [],
|
||||
);
|
||||
const [headers, setHeaders] = useState<[string, string, boolean?][]>(
|
||||
props.headers || [],
|
||||
props?.headers || [],
|
||||
);
|
||||
const [body, setBody] = useState<string | undefined>(props.body);
|
||||
const [method, setMethod] = useState<string>(props.method || 'GET');
|
||||
const [body, setBody] = useState<string | undefined>(props?.body);
|
||||
const [method, setMethod] = useState<string>(props?.method || 'GET');
|
||||
const [response, setResponse] = useState<Response | null>(
|
||||
props.response || null,
|
||||
props?.response || null,
|
||||
);
|
||||
|
||||
const url = urlify(_url);
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
import React, { ReactElement } from 'react';
|
||||
import RequestDetail from '../../components/RequestDetail';
|
||||
import { useParams } from 'react-router';
|
||||
import { useRequest } from '../../reducers/requests';
|
||||
|
||||
export default function Request(): ReactElement {
|
||||
const params = useParams<{ requestId: string }>();
|
||||
|
||||
return (
|
||||
<>
|
||||
<RequestDetail requestId={params.requestId} />
|
||||
</>
|
||||
<>{!!params.requestId && <RequestDetail requestId={params.requestId} />}</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ const initialState: State = {
|
||||
order: [],
|
||||
};
|
||||
|
||||
export const addRequestHistory = (request: RequestHistory) => {
|
||||
export const addRequestHistory = (request?: RequestHistory | null) => {
|
||||
return {
|
||||
type: ActionType['/history/addRequest'],
|
||||
payload: request,
|
||||
@@ -56,6 +56,9 @@ export default function history(
|
||||
switch (action.type) {
|
||||
case ActionType['/history/addRequest']: {
|
||||
const payload: RequestHistory = action.payload;
|
||||
|
||||
if (!payload) return state;
|
||||
|
||||
const existing = state.map[payload.id];
|
||||
const newMap = {
|
||||
...state.map,
|
||||
@@ -91,8 +94,9 @@ export const useHistoryOrder = (): string[] => {
|
||||
}, deepEqual);
|
||||
};
|
||||
|
||||
export const useRequestHistory = (id: string): RequestHistory | undefined => {
|
||||
export const useRequestHistory = (id?: string): RequestHistory | undefined => {
|
||||
return useSelector((state: AppRootState) => {
|
||||
if (!id) return undefined;
|
||||
return state.history.map[id];
|
||||
}, deepEqual);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { type RequestLog, type RequestHistory } from '../pages/Background/actionTypes';
|
||||
import {
|
||||
type RequestLog,
|
||||
type RequestHistory,
|
||||
} from '../pages/Background/actionTypes';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { AppRootState } from './index';
|
||||
import deepEqual from 'fast-deep-equal';
|
||||
@@ -36,22 +39,10 @@ export const setRequests = (requests: RequestLog[]): Action<RequestLog[]> => ({
|
||||
});
|
||||
|
||||
export const notarizeRequest = (options: RequestHistory) => async () => {
|
||||
const notaryUrl = await get(NOTARY_API_LS_KEY);
|
||||
const websocketProxyUrl = await get(PROXY_API_LS_KEY);
|
||||
|
||||
console.log({
|
||||
type: BackgroundActiontype.prove_request_start,
|
||||
data: {
|
||||
url: options.url,
|
||||
method: options.method,
|
||||
headers: options.headers,
|
||||
body: options.body,
|
||||
maxTranscriptSize: options.maxTranscriptSize,
|
||||
notaryUrl,
|
||||
websocketProxyUrl,
|
||||
},
|
||||
})
|
||||
const notaryUrl = await get(NOTARY_API_LS_KEY, 'https://127.0.0.1:7047');
|
||||
const websocketProxyUrl = await get(PROXY_API_LS_KEY, 'ws://127.0.0.1:55688');
|
||||
|
||||
console.log({ notaryUrl, websocketProxyUrl });
|
||||
chrome.runtime.sendMessage<any, string>({
|
||||
type: BackgroundActiontype.prove_request_start,
|
||||
data: {
|
||||
@@ -64,7 +55,7 @@ export const notarizeRequest = (options: RequestHistory) => async () => {
|
||||
websocketProxyUrl,
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const setActiveTab = (
|
||||
activeTab: chrome.tabs.Tab | null,
|
||||
|
||||
@@ -17,15 +17,18 @@ export function urlify(
|
||||
}
|
||||
}
|
||||
|
||||
export function devlog(text: string) {
|
||||
export function devlog(...args: any[]) {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.log(text);
|
||||
console.log(...args);
|
||||
}
|
||||
}
|
||||
|
||||
export function download(filename: string, content: string) {
|
||||
var element = document.createElement('a');
|
||||
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(content));
|
||||
const element = document.createElement('a');
|
||||
element.setAttribute(
|
||||
'href',
|
||||
'data:text/plain;charset=utf-8,' + encodeURIComponent(content),
|
||||
);
|
||||
element.setAttribute('download', filename);
|
||||
|
||||
element.style.display = 'none';
|
||||
|
||||
@@ -6,9 +6,9 @@ export async function set(key: string, value: string) {
|
||||
return chrome.storage.sync.set({ [key]: value });
|
||||
}
|
||||
|
||||
export async function get(key: string) {
|
||||
export async function get(key: string, defaultValue?: string) {
|
||||
return chrome.storage.sync
|
||||
.get(key)
|
||||
.then((json: any) => json[key])
|
||||
.then((json: any) => json[key] || defaultValue)
|
||||
.catch(() => '');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user