Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: File upload loses original file name #848

Open
strongpauly opened this issue Aug 23, 2024 · 1 comment
Open

[Bug]: File upload loses original file name #848

strongpauly opened this issue Aug 23, 2024 · 1 comment
Labels
bug Something isn't working

Comments

@strongpauly
Copy link

strongpauly commented Aug 23, 2024

Bug Description

When following the example https://github.com/zapier/zapier-platform/blob/main/example-apps/files/creates/uploadFile_v10.js the file that is uploaded does not retain its original name. Instead we get a seemingly random sequence of characters as the name.
I can see that the example expects the consumer to specify the name as a separate field, but it would be good to not require the user to do this.

Reproduction Steps

  1. Create an app which uploads a file from a single field as the above example
  2. Send a file to that app with a meaningful name

Zapier Platform version

  • CLI version: 15.12.0
  • Node.js version: v20.10.0
  • OS info: darwin-arm64
  • zapier-platform-core dependency: 15.12.0

Node.js version

v20.10.0

Your Operating System

macOS 14.5

npm/yarn version

4.4.0

App ID

147940

More Details

No response

@strongpauly strongpauly added the bug Something isn't working label Aug 23, 2024
@Starfox64
Copy link

I've found a solution to this issue, turns out the endpoint generated by Zapier to download the file keeps the filename in the Content-Disposition header. It is therefore possible to access it when we download the file in preparation for the upload.

const http = require('https');
const FormData = require('form-data');

function getFileName(disposition) {
  const utf8FilenameRegex = /filename\*=UTF-8''([\w%\-\.]+)(?:; ?|$)/i;
  const asciiFilenameRegex = /^filename=(["']?)(.*?[^\\])\1(?:; ?|$)/i;

  let fileName = 'attachment.bin';
  if (utf8FilenameRegex.test(disposition)) {
    fileName = decodeURIComponent(utf8FilenameRegex.exec(disposition)[1]);
  } else {
    // prevent ReDos attacks by anchoring the ascii regex to string start and
    //  slicing off everything before 'filename='
    const filenameStart = disposition.toLowerCase().indexOf('filename=');
    if (filenameStart >= 0) {
      const partialDisposition = disposition.slice(filenameStart);
      const matches = asciiFilenameRegex.exec(partialDisposition );
      if (matches != null && matches[2]) {
        fileName = matches[2];
      }
    }
  }
  return fileName;
}

function makeDownloadStream(url) {
  return new Promise((resolve, reject) => {
    http
      .request(url, (res) => {
        // We can risk missing the first n bytes if we don't pause!
        res.pause();

        const filename = getFileName(res.headers['content-disposition']);

        resolve({ stream: res, filename });
      })
      .on('error', reject)
      .end();
  });
}

// NOTE: The above function now returns an object with both the stream and filename instead of just the stream
// Change downstream code accordingly
// ie.

// ...
form.append('file', stream.stream, stream.filename);

// All set! Resume the stream
stream.stream.resume();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants