Skip to content

File upload/download in js

Converting a buffer to a base64-string

 Buffer.from(buffer.Body, 'binary').toString('base64')

Serializing a buffer (JSON.stringify(buffer)) can increase the content size (JSON.stringify(biuffer).length) a lot. It might be better to convert the buffer to a base64 string when transporting it between different backends. File-upload from frontend to backend usually happens through a buffer.

Uploading a file to S3

        const body = typeof fileToUpload === 'string' ? Buffer.from(fileToUpload as string, 'base64') : (fileToUpload as { file: FileUpload }).file?.createReadStream(); // second option is in the case of an upload through graphql-upload package

    const RAND_BYTE_LENGTH = 20;
        const rnd = crypto.randomBytes(RAND_BYTE_LENGTH);
        hash = crypto 
          .createHash('sha256')
          .update(name + rnd) 
          .digest('hex'); 
        const keyName = `${S3_fOLDER}/${hash}`;

        if (!body) {
          throw new Error('No file to upload found');
        }

        const params = {
          Bucket: process.env.S3_BUCKET,
          Key: keyName,
          Body: body,
          ContentType: /* mimetype of file */,
        };

        await this.s3.upload(params).promise();

Creating a presigned url from S3

      const params = {
        Bucket: process.env.S3_BUCKET,
        Key: `${S3_fOLDER}/${hash}`,
        Expires: 3600, // 60 min
        ResponseContentDisposition: download ? undefined : 'inline',
        ResponseContentType: download ? undefined : mimetype,
      };
      return await this.s3.getSignedUrlPromise('getObject', params);
    

Showing a base64 file in the browser

For images

<img  src=`data:${type};base64,${base64}`/>

For pdf

    const pdfWindow = window.open('');
    const binStr = atob(base64);
    const len = binStr.length;
    const arr = new Uint8Array(len);
    for (let i = 0; i < len; i++) {
      arr[i] = binStr.charCodeAt(i);
    }
    const blob = new Blob([arr], { type: 'application/pdf' });
    const url = URL.createObjectURL(blob);

    pdfWindow?.document.write('<html<head><style>body{margin: 0px;}iframe{border-width: 0px;}</style></head>');
    pdfWindow?.document.write(`<body><embed width='100%' height='100%' src='${url}'></embed></body></html>`);

File upload protection defaults

By default , node has a file-upload limit. (= Payload to large error in backend terminal) Solve it by highering the limits:

  app.use(json({ limit: '50mb' }));
  app.use(urlencoded({ extended: true, limit: '50mb' }));

By default, nginx prevents a file upload bigger then 1Mb. (Payload too large error in frontend network tab with no size limit specified and a ref to nginx) . Solve it by adding annotations to the config files:

for ingress: nginx.ingress.kubernetes.io/proxy-body-size: 25m
for nginx config:client_max_body_size 25M;

Request CSP headers on a frontend to backend call, can prevent certain visualisatons. For example obj-src ‘self’ will prevent a pdf from viewing inside an embed-tag. Check the following tool for security

Chrome prevents the preview of an embedded data:-src that is bigger then 1-2Mb (The screen that shows the pdf stays blank). Therefore it is better to use a blob. (See code in showing a pdf in browser)

Published inJSNode

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *