Skip to content

Commit

Permalink
basic plugin for twitter and reddit (#26)
Browse files Browse the repository at this point in the history
* basic plugin for twitter and reddit

* remove timeout

* linter fix
  • Loading branch information
0xtsukino authored Nov 14, 2023
1 parent d09aeca commit 5acf706
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 17 deletions.
108 changes: 93 additions & 15 deletions src/pages/Home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,22 @@ import React, {
import Icon from '../../components/Icon';
import classNames from 'classnames';
import { useNavigate } from 'react-router';
import { useActiveTabUrl, useRequests } from '../../reducers/requests';
import {
notarizeRequest,
useActiveTabUrl,
useRequests,
} from '../../reducers/requests';
import { Link } from 'react-router-dom';
import { filterByBookmarks } from '../../../utils/bookmark';
import bookmarks from '../../../utils/bookmark/bookmarks.json';
import { replayRequest, urlify } from '../../utils/misc';
import { useDispatch } from 'react-redux';
import { get, NOTARY_API_LS_KEY, PROXY_API_LS_KEY } from '../../utils/storage';

export default function Home(): ReactElement {
const requests = useRequests();
const url = useActiveTabUrl();
const navigate = useNavigate();
const suggestions = filterByBookmarks(requests);
const dispatch = useDispatch();

return (
<div className="flex flex-col gap-4 py-4 overflow-y-auto">
Expand Down Expand Up @@ -44,7 +51,7 @@ export default function Home(): ReactElement {
Options
</NavButton>
</div>
{!suggestions.length && (
{!bookmarks.length && (
<div className="flex flex-col flex-nowrap">
<div className="flex flex-col items-center justify-center text-slate-300 cursor-default select-none">
<div>No available notarization for {url?.hostname}</div>
Expand All @@ -55,12 +62,15 @@ export default function Home(): ReactElement {
</div>
)}
<div className="flex flex-col px-4 gap-4">
{suggestions.map((bm, i) => {
{bookmarks.map((bm, i) => {
try {
const reqs = requests.filter((req) => {
return req?.url?.includes(bm.url);
});

const bmHost = urlify(bm.targetUrl)?.host;
const isReady = !!reqs.length;

return (
<div
key={i}
Expand All @@ -76,17 +86,85 @@ export default function Home(): ReactElement {
</div>
<div className="font-bold">{bm.title}</div>
<div className="italic">{bm.description}</div>
<div className="text-slate-300">
Found {reqs.length} request
</div>
{reqs.map((r) => (
<Link
to={`/requests/${r.requestId}`}
className="break-all text-slate-500 truncate"
{isReady && (
<button
className="button button--primary w-fit self-end mt-2"
onClick={async () => {
if (!isReady) return;

const req = reqs[0];
const res = await replayRequest(req);
const secretHeaders = req.requestHeaders
.map((h) => {
return (
`${h.name.toLowerCase()}: ${h.value || ''}` || ''
);
})
.filter((d) => !!d);
const selectedValue = res.match(
new RegExp(bm.responseSelector, 'g'),
);

if (selectedValue) {
const revealed = bm.valueTransform.replace(
'%s',
selectedValue[0],
);
const selectionStart = res.indexOf(revealed);
const selectionEnd =
selectionStart + revealed.length - 1;
const secretResps = [
res.substring(0, selectionStart),
res.substring(selectionEnd, res.length),
].filter((d) => !!d);

const hostname = urlify(req.url)?.hostname;
const notaryUrl = await get(NOTARY_API_LS_KEY);
const websocketProxyUrl = await get(PROXY_API_LS_KEY);

const headers: { [k: string]: string } =
req.requestHeaders.reduce(
(acc: any, h) => {
acc[h.name] = h.value;
return acc;
},
{ Host: hostname },
);

//TODO: for some reason, these needs to be override to work
headers['Accept-Encoding'] = 'identity';
headers['Connection'] = 'close';

dispatch(
// @ts-ignore
notarizeRequest({
url: req.url,
method: req.method,
headers: headers,
body: req.requestBody,
maxTranscriptSize: 16384,
notaryUrl,
websocketProxyUrl,
secretHeaders,
secretResps,
}),
);

navigate(`/history`);
}
}}
>
Notarize
</button>
)}
{!isReady && (
<button
className="button w-fit self-end mt-2"
onClick={() => chrome.tabs.update({ url: bm.targetUrl })}
>
{r.url}
</Link>
))}
{`Go to ${bmHost}`}
</button>
)}
</div>
);
} catch (e) {
Expand Down
15 changes: 15 additions & 0 deletions src/pages/Popup/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,21 @@ code {
@apply text-slate-700;
}

&--primary {
@apply bg-primary/[0.8];
@apply text-white;

&:hover {
@apply bg-primary/[0.9];
@apply text-white;
}

&:active {
@apply bg-primary;
@apply text-white;
}
}

&:disabled {
@apply opacity-50;
@apply select-none;
Expand Down
40 changes: 40 additions & 0 deletions src/utils/misc.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { RequestLog } from '../pages/Background/actionTypes';

export function urlify(
text: string,
params?: [string, string, boolean?][],
Expand Down Expand Up @@ -38,3 +40,41 @@ export function download(filename: string, content: string) {

document.body.removeChild(element);
}

export async function replayRequest(req: RequestLog): Promise<string> {
const options = {
method: req.method,
headers: req.requestHeaders.reduce(
(acc: { [key: string]: string }, h: chrome.webRequest.HttpHeader) => {
if (typeof h.name !== 'undefined' && typeof h.value !== 'undefined') {
acc[h.name] = h.value;
}
return acc;
},
{},
),
body: req.requestBody,
};

if (req?.formData) {
const formData = new URLSearchParams();
Object.entries(req.formData).forEach(([key, values]) => {
values.forEach((v) => formData.append(key, v));
});
options.body = formData.toString();
}

const resp = await fetch(req.url, options);
const contentType =
resp?.headers.get('content-type') || resp?.headers.get('Content-Type');

if (contentType?.includes('application/json')) {
return resp.text();
} else if (contentType?.includes('text')) {
return resp.text();
} else if (contentType?.includes('image')) {
return resp.blob().then((blob) => blob.text());
} else {
return resp.blob().then((blob) => blob.text());
}
}
10 changes: 8 additions & 2 deletions utils/bookmark/bookmarks.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
[
{
"url": "https://api.twitter.com/1.1/account/settings.json",
"targetUrl": "https://www.twitter.com",
"method": "GET",
"type": "xmlhttprequest",
"title": "Twitter Profile",
"description": "Notarize ownership of a twitter profile. To start, go to your own profile"
"description": "Notarize ownership of a twitter profile. To start, go to your own profile",
"responseSelector": "(?<=\"screen_name\":)\"(.*?)\"",
"valueTransform": "\"screen_name\":%s"
},
{
"url": "https://gateway.reddit.com/desktopapi/v1/prefs",
"targetUrl": "https://www.reddit.com/settings",
"method": "GET",
"type": "xmlhttprequest",
"title": "Reddit Profile",
"description": "Notarize ownership of a reddit profile. To start, go to reddit.com/settings"
"description": "Notarize ownership of a reddit profile. To start, go to reddit.com/settings",
"responseSelector": "(?<=\"displayText\": )\"(.*?)\"",
"valueTransform": "\"displayText\": %s"
}
]

0 comments on commit 5acf706

Please sign in to comment.