Skip to content

Commit 1bcfd66

Browse files
committed
feat(web): add-authentication-to-file-uploads
1 parent a2ed358 commit 1bcfd66

File tree

4 files changed

+64
-56
lines changed

4 files changed

+64
-56
lines changed

web/netlify/functions/uploadToIPFS.ts

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { File, FilebaseClient } from "@filebase/client";
2-
import { Handler } from "@netlify/functions";
2+
import middy from "@middy/core";
33
import amqp, { Connection } from "amqplib";
44
import busboy from "busboy";
55

6-
const { FILEBASE_TOKEN, RABBITMQ_URL, FILEBASE_API_WRAPPER } = process.env;
6+
import { authMiddleware } from "../middleware/authMiddleware";
7+
8+
const { FILEBASE_TOKEN, RABBITMQ_URL } = process.env;
79
const filebase = new FilebaseClient({ token: FILEBASE_TOKEN ?? "" });
810

911
type FormElement =
@@ -65,24 +67,17 @@ const pinToFilebase = async (data: FormData, operation: string): Promise<Array<s
6567
return cids;
6668
};
6769

68-
export const handler: Handler = async (event) => {
70+
export const uploadToIPFS = async (event) => {
6971
const { queryStringParameters } = event;
7072

71-
if (!queryStringParameters || !queryStringParameters.key || !queryStringParameters.operation) {
73+
if (!queryStringParameters?.operation) {
7274
return {
7375
statusCode: 400,
7476
body: JSON.stringify({ message: "Invalid query parameters" }),
7577
};
7678
}
7779

78-
const { key, operation } = queryStringParameters;
79-
80-
if (key !== FILEBASE_API_WRAPPER) {
81-
return {
82-
statusCode: 403,
83-
body: JSON.stringify({ message: "Invalid API key" }),
84-
};
85-
}
80+
const { operation } = queryStringParameters;
8681

8782
try {
8883
const parsed = await parseMultipart(event);
@@ -102,3 +97,5 @@ export const handler: Handler = async (event) => {
10297
};
10398
}
10499
};
100+
101+
export const handler = middy(uploadToIPFS).use(authMiddleware());

web/src/pages/Cases/CaseDetails/Evidence/SubmitEvidenceModal.tsx

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { prepareWriteEvidenceModule } from "hooks/contracts/generated";
1111
import { uploadFormDataToIPFS } from "utils/uploadFormDataToIPFS";
1212
import { wrapWithToast, OPTIONS as toastOptions } from "utils/wrapWithToast";
1313

14+
import { EnsureAuth } from "components/EnsureAuth";
1415
import { EnsureChain } from "components/EnsureChain";
1516

1617
const StyledModal = styled(Modal)`
@@ -67,35 +68,37 @@ const SubmitEvidenceModal: React.FC<{
6768
<ButtonArea>
6869
<Button variant="secondary" disabled={isSending} text="Return" onClick={close} />
6970
<EnsureChain>
70-
<Button
71-
text="Submit"
72-
isLoading={isSending}
73-
disabled={isSending}
74-
onClick={async () => {
75-
setIsSending(true);
76-
toast.info("Uploading to IPFS", toastOptions);
77-
const formData = await constructEvidence(message, file);
78-
uploadFormDataToIPFS(formData)
79-
.then(async (res) => {
80-
const response = await res.json();
81-
if (res.status === 200 && walletClient) {
82-
const cid = response["cids"][0];
83-
const { request } = await prepareWriteEvidenceModule({
84-
functionName: "submitEvidence",
85-
args: [BigInt(evidenceGroup), cid],
86-
});
87-
await wrapWithToast(async () => await walletClient.writeContract(request), publicClient).then(
88-
() => {
89-
setMessage("");
90-
close();
91-
}
92-
);
93-
}
94-
})
95-
.catch()
96-
.finally(() => setIsSending(false));
97-
}}
98-
/>
71+
<EnsureAuth>
72+
<Button
73+
text="Submit"
74+
isLoading={isSending}
75+
disabled={isSending}
76+
onClick={async () => {
77+
setIsSending(true);
78+
toast.info("Uploading to IPFS", toastOptions);
79+
const formData = await constructEvidence(message, file);
80+
uploadFormDataToIPFS(formData)
81+
.then(async (res) => {
82+
const response = await res.json();
83+
if (res.status === 200 && walletClient) {
84+
const cid = response["cids"][0];
85+
const { request } = await prepareWriteEvidenceModule({
86+
functionName: "submitEvidence",
87+
args: [BigInt(evidenceGroup), cid],
88+
});
89+
await wrapWithToast(async () => await walletClient.writeContract(request), publicClient).then(
90+
() => {
91+
setMessage("");
92+
close();
93+
}
94+
);
95+
}
96+
})
97+
.catch()
98+
.finally(() => setIsSending(false));
99+
}}
100+
/>
101+
</EnsureAuth>
99102
</EnsureChain>
100103
</ButtonArea>
101104
</StyledModal>

web/src/pages/Resolver/index.tsx

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { landscapeStyle } from "styles/landscapeStyle";
88
import { responsiveSize } from "styles/responsiveSize";
99

1010
import ConnectWallet from "components/ConnectWallet";
11+
import { EnsureAuth } from "components/EnsureAuth";
1112
import HeroImage from "components/HeroImage";
1213

1314
import Description from "./Briefing/Description";
@@ -71,21 +72,23 @@ const DisputeResolver: React.FC = () => {
7172
<Container>
7273
{isConnected && !isPreviewPage ? <StyledLabel>Start a case</StyledLabel> : null}
7374
{isConnected ? (
74-
<MiddleContentContainer>
75-
{isConnected && !isPreviewPage ? <Timeline /> : null}
76-
<Routes>
77-
<Route index element={<Navigate to="title" replace />} />
78-
<Route path="/title/*" element={<Title />} />
79-
<Route path="/description/*" element={<Description />} />
80-
<Route path="/court/*" element={<Court />} />
81-
<Route path="/category/*" element={<Category />} />
82-
<Route path="/jurors/*" element={<Jurors />} />
83-
<Route path="/voting-options/*" element={<VotingOptions />} />
84-
<Route path="/notable-persons/*" element={<NotablePersons />} />
85-
<Route path="/policy/*" element={<Policy />} />
86-
<Route path="/preview/*" element={<Preview />} />
87-
</Routes>
88-
</MiddleContentContainer>
75+
<EnsureAuth>
76+
<MiddleContentContainer>
77+
{isConnected && !isPreviewPage ? <Timeline /> : null}
78+
<Routes>
79+
<Route index element={<Navigate to="title" replace />} />
80+
<Route path="/title/*" element={<Title />} />
81+
<Route path="/description/*" element={<Description />} />
82+
<Route path="/court/*" element={<Court />} />
83+
<Route path="/category/*" element={<Category />} />
84+
<Route path="/jurors/*" element={<Jurors />} />
85+
<Route path="/voting-options/*" element={<VotingOptions />} />
86+
<Route path="/notable-persons/*" element={<NotablePersons />} />
87+
<Route path="/policy/*" element={<Policy />} />
88+
<Route path="/preview/*" element={<Preview />} />
89+
</Routes>
90+
</MiddleContentContainer>
91+
</EnsureAuth>
8992
) : (
9093
<ConnectWalletContainer>
9194
To create a new dispute, connect first

web/src/utils/uploadFormDataToIPFS.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,14 @@ import { toast } from "react-toastify";
33
import { OPTIONS } from "utils/wrapWithToast";
44

55
export function uploadFormDataToIPFS(formData: FormData, operation = "evidence"): Promise<Response> {
6+
const authToken = sessionStorage.getItem("auth-token")?.replace(/"/g, "");
7+
68
return toast.promise<Response, Error>(
79
fetch(`/.netlify/functions/uploadToIPFS?key=kleros-v2&operation=${operation}`, {
810
method: "POST",
11+
headers: {
12+
"x-auth-token": authToken ?? "",
13+
},
914
body: formData,
1015
}).then(async (response) => {
1116
if (response.status !== 200) {

0 commit comments

Comments
 (0)