Skip to content

Commit

Permalink
Multiple Redactions during Notarization process (#81)
Browse files Browse the repository at this point in the history
  • Loading branch information
Codetrauma authored Oct 9, 2024
1 parent f6e5820 commit 2db735e
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 51 deletions.
1 change: 0 additions & 1 deletion src/components/RequestDetail/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import {
getMaxSent,
} from '../../utils/storage';
import { MAX_RECV, MAX_SENT } from '../../utils/constants';
import { urlify } from '../../utils/misc';

type Props = {
requestId: string;
Expand Down
18 changes: 8 additions & 10 deletions src/entries/Background/rpc.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import browser from 'webextension-polyfill';
import { clearCache, getCacheByTabId } from './cache';
import { addRequestHistory } from '../../reducers/history';
import { addRequestHistory, setRequests } from '../../reducers/history';
import {
addNotaryRequest,
addNotaryRequestProofs,
Expand Down Expand Up @@ -224,15 +224,13 @@ function handleGetProveRequests(
sendResponse: (data?: any) => void,
): boolean {
getNotaryRequests().then(async (reqs) => {
for (const req of reqs.reverse()) {
await browser.runtime.sendMessage({
type: BackgroundActiontype.push_action,
data: {
tabId: 'background',
},
action: addRequestHistory(req),
});
}
await browser.runtime.sendMessage({
type: BackgroundActiontype.push_action,
data: {
tabId: 'background',
},
action: setRequests(reqs),
});
sendResponse(reqs);
});

Expand Down
8 changes: 5 additions & 3 deletions src/pages/History/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ export default function History(): ReactElement {

return (
<div className="flex flex-col flex-nowrap overflow-y-auto">
{history.map((id) => {
return <OneRequestHistory key={id} requestId={id} />;
})}
{history
.map((id) => {
return <OneRequestHistory key={id} requestId={id} />;
})
.reverse()}
</div>
);
}
Expand Down
129 changes: 92 additions & 37 deletions src/pages/Notarize/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import React, {
ReactEventHandler,
useEffect,
useRef,
useMemo,
} from 'react';
import { useNavigate, useParams } from 'react-router';
import { notarizeRequest, useRequest } from '../../reducers/requests';
Expand Down Expand Up @@ -278,34 +279,79 @@ export function RevealHeaderTable(props: {
);
}

function HideResponseStep(props: {
export function HideResponseStep(props: {
onNext: () => void;
onCancel: () => void;
setSecretResps: (secrets: string[]) => void;
}): ReactElement {
}): React.ReactElement {
const params = useParams<{ requestId: string }>();
const req = useRequest(params.requestId);
const [responseText, setResponseText] = useState('');
const [start, setStart] = useState(0);
const [end, setEnd] = useState(0);
const [redactedRanges, setRedactedRanges] = useState<
{ start: number; end: number }[]
>([]);
const [isRedactMode, setIsRedactMode] = useState(true);
const taRef = useRef<HTMLTextAreaElement | null>(null);

const onSelectionChange: ReactEventHandler<HTMLTextAreaElement> = useCallback(
(e) => {
const ta = e.currentTarget;
if (ta.selectionEnd > ta.selectionStart) {
setStart(ta.selectionStart);
setEnd(ta.selectionEnd);
props.setSecretResps(
[
responseText.substring(0, ta.selectionStart),
responseText.substring(ta.selectionEnd, responseText.length),
].filter((d) => !!d),
);
const onSelectionChange: React.MouseEventHandler<HTMLTextAreaElement> =
useCallback(
(e) => {
const ta = e.currentTarget;
if (isRedactMode && ta.selectionEnd > ta.selectionStart) {
const newRange: { start: number; end: number } = {
start: ta.selectionStart,
end: ta.selectionEnd,
};

setRedactedRanges((prevRanges) => {
let updatedRanges = [...prevRanges, newRange].sort(
(a, b) => a.start - b.start,
);
updatedRanges = mergeRanges(updatedRanges);

const secretResps = updatedRanges
.map(({ start, end }) => responseText.substring(start, end))
.filter((d) => !!d);
props.setSecretResps(secretResps);

return updatedRanges;
});
} else if (!isRedactMode) {
const clickPosition = ta.selectionStart;
setRedactedRanges((prevRanges) => {
const updatedRanges = prevRanges.filter(
({ start, end }) => clickPosition < start || clickPosition > end,
);

const secretResps = updatedRanges
.map(({ start, end }) => responseText.substring(start, end))
.filter((d) => !!d);
props.setSecretResps(secretResps);

return updatedRanges;
});
}
},
[responseText, props, isRedactMode],
);

const mergeRanges = (
ranges: { start: number; end: number }[],
): { start: number; end: number }[] => {
if (ranges.length === 0) return [];
const mergedRanges: { start: number; end: number }[] = [ranges[0]];

for (let i = 1; i < ranges.length; i++) {
const lastRange = mergedRanges[mergedRanges.length - 1];
if (ranges[i].start <= lastRange.end) {
lastRange.end = Math.max(lastRange.end, ranges[i].end);
} else {
mergedRanges.push(ranges[i]);
}
},
[responseText],
);
}

return mergedRanges;
};

useEffect(() => {
if (!req) return;
Expand Down Expand Up @@ -341,37 +387,46 @@ function HideResponseStep(props: {

if (current) {
current.focus();
current.setSelectionRange(start, end);
}
}, [taRef, start, end]);
}, [taRef]);

if (!req) return <></>;

let shieldedText = '';

if (end > start) {
shieldedText = Array(start)
.fill('*')
.join('')
.concat(responseText.substring(start, end))
.concat(
Array(responseText.length - end)
.fill('*')
.join(''),
);
}
const shieldedText = responseText.split('');
redactedRanges.forEach(({ start, end }) => {
for (let i = start; i < end; i++) {
shieldedText[i] = '*';
}
});

return (
<div className="flex flex-col flex-nowrap flex-shrink flex-grow h-0">
<div className="border bg-primary/[0.9] text-white border-slate-300 py-1 px-2 font-semibold">
Step 2 of 2: Highlight text to show only selected text from response
Step 2 of 2:{' '}
{isRedactMode
? 'Highlight text to redact selected portions'
: 'Click redacted text to unredact'}
</div>
<div className="flex flex-row justify-end p-0.5 gap-2 border-t">
<button
className={`bg-${isRedactMode ? 'red-500' : 'green-500'} text-white font-bold hover:bg-${isRedactMode ? 'red-400' : 'green-400'} px-2 py-0.5 active:bg-${isRedactMode ? 'red-600' : 'green-600'}`}
onClick={() => setIsRedactMode(!isRedactMode)}
>
{isRedactMode ? 'Unredact Text' : 'Redact Text'}
</button>
<button
className="bg-gray-500 text-white font-bold hover:bg-gray-400 px-2 py-0.5 active:bg-gray-600"
onClick={() => setRedactedRanges([])}
>
Unredact All
</button>
</div>
<div className="flex flex-col flex-grow flex-shrink h-0 overflow-y-auto p-2">
<textarea
ref={taRef}
className="flex-grow textarea bg-slate-100 font-mono"
value={shieldedText || responseText}
onSelect={onSelectionChange}
value={shieldedText.join('')}
onMouseUp={onSelectionChange}
/>
</div>
<div className="flex flex-row justify-end p-2 gap-2 border-t">
Expand Down
20 changes: 20 additions & 0 deletions src/reducers/history.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import deepEqual from 'fast-deep-equal';

enum ActionType {
'/history/addRequest' = '/history/addRequest',
'/history/setRequests' = '/history/setRequests',
'/history/deleteRequest' = '/history/deleteRequest',
}

Expand Down Expand Up @@ -37,6 +38,13 @@ export const addRequestHistory = (request?: RequestHistory | null) => {
};
};

export const setRequests = (requests: RequestHistory[]) => {
return {
type: ActionType['/history/setRequests'],
payload: requests,
};
};

export const deleteRequestHistory = (id: string) => {
chrome.runtime.sendMessage<any, string>({
type: BackgroundActiontype.delete_prove_request,
Expand Down Expand Up @@ -72,6 +80,18 @@ export default function history(
order: newOrder,
};
}
case ActionType['/history/setRequests']: {
const payload: RequestHistory[] = action.payload;

return {
...state,
map: payload.reduce((map: { [id: string]: RequestHistory }, req) => {
map[req.id] = req;
return map;
}, {}),
order: payload.map(({ id }) => id),
};
}
case ActionType['/history/deleteRequest']: {
const reqId: string = action.payload;
const newMap = { ...state.map };
Expand Down

0 comments on commit 2db735e

Please sign in to comment.