My nextjs app (v12.1.3) allows users to upload files. The server stores them in an AWS s3 bucket.
I store them in this way:
import _ from 'lodash';
import AWS from 'aws-sdk';
import { v4 as uuidv4 } from 'uuid';
import { config } from '../config';
// file is in base64 format
const uploadFileToS3 = async (file: string) => {
const s3 = new AWS.S3({
accessKeyId: config.AWS_ACCESS_KEY_ID,
secretAccessKey: config.AWS_SECRET_ACCESS_KEY,
signatureVersion: 'v4',
region: 'eu-south-1',
});
const contentType = file.split(':')[1].split(';')[0];
const params = {
Key: uuidv4(),
Body: Buffer.from(file.replace(/^data:.+;base64,/, ''), 'base64'),
Bucket: config.AWS_S3_BUCKET_NAME,
ContentType: contentType,
};
return await s3.upload(params).promise();
};
export default uploadFileToS3;
My bucket settings:
Block public access (bucket settings) -> OFF
Bucket policy
{ "Version": "2012-10-17", "Statement": [ { "Sid": "PublicReadGetObject", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::my-test-bucket/*" } ] }
Cross-origin resource sharing (CORS)
[ { "AllowedHeaders": [], "AllowedMethods": [ "GET" ], "AllowedOrigins": [ "*" ], "ExposeHeaders": [] } ]
I store in my mongo DB the url returned from uploadFileToS3
method.
Client side, instead, I use this url to view images and pdf files. The problem is that on a certain route /generic-entity/{id}
I cannot preview the .pdf files (there is no problems with .jpeg or .png files).
I get this error (even it is a warning):
Cross-Origin Read Blocking (CORB) blocked cross-origin response https://xxxxxx.execute-api.us-east-2.amazonaws.com/default/xxxxxx with MIME type application/pdf. See https://www.chromestatus.com/feature/5629709824032768 for more details.
and I looked around and found out it is a new web platform security feature that helps mitigate the threat of side-channel attacks
Instead on the route /generic-entity
I can preview the pdf files. The difference is that on this last one there is a automatic GET to the aws like this one:
curl 'https://my-test-bucket.s3.eu-south-1.amazonaws.com/e751b456-c996-4747-bcef-03021cd80357__foo__Doc%2520base.pdf' \
-H 'Accept: */*' \
-H 'Accept-Language: en,en-US;q=0.9,it-IT;q=0.8,it;q=0.7' \
-H 'Connection: keep-alive' \
-H 'If-Modified-Since: Sun, 26 Jun 2022 19:21:16 GMT' \
-H 'If-None-Match: "9b1027ca72e993b2607ba5b54e735c64"' \
-H 'Origin: http://localhost:3000' \
-H 'Referer: http://localhost:3000/' \
-H 'Sec-Fetch-Dest: empty' \
-H 'Sec-Fetch-Mode: cors' \
-H 'Sec-Fetch-Site: cross-site' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36' \
-H 'sec-ch-ua: ".Not/A)Brand";v="99", "Google Chrome";v="103", "Chromium";v="103"' \
-H 'sec-ch-ua-mobile: ?0' \
-H 'sec-ch-ua-platform: "macOS"' \
--compressed
on the other one instead there's is none. I tried to do it manually but it didn't solve the problem.
For major details here's the react component I use to preview the pdf file:
// import default react-pdf entry
import { Document, Page, pdfjs } from 'react-pdf';
// import pdf worker as a url, see `next.config.js` and `pdf-worker.js`
import workerSrc from '../../pdf-worker';
pdfjs.GlobalWorkerOptions.workerSrc = workerSrc;
interface Props {
file: any;
className?: string;
}
//in this case file is a url.
const PDFPreview: React.FC<Props> = ({ file, className }) => {
function onDocumentLoadSuccess() {
document
.getElementById('react-pdf__Page__canvas')
?.style.setProperty('display', 'flex', 'important');
}
return (
<div
className={`flex overflow-y-hidden rounded-lg cursor-pointer ${className}`}
>
<Document file={file} onLoadSuccess={onDocumentLoadSuccess}>
<Page
key={`page_${1}`}
pageNumber={1}
renderAnnotationLayer={false}
renderTextLayer={false}
className="flex w-full"
style={{ display: 'flex' }}
/>
</Document>
</div>
);
};
export default PDFPreview;
Do you have any suggestion on how to fix this?
P.S. I also replicated this error in this github repo and I deployed it on vercel. You can see that on the route /my-entity
it works, while on the route /my-entity/1
doesn't using the same url and the same react component