tus/tus-node-server

`generateUrl` returns insecure URL and subsequent chunk uploads fail

Closed this issue · 2 comments

mfts commented

Initial checklist

  • I understand this is a bug report and questions should be posted in the Community Forum
  • I searched issues and couldn’t find anything (or linked relevant results below)

Steps to reproduce

I'm using @tus/server with next.js pages router.

I set up my api route: pages/api/file/tus/[[...file]].ts

import type { NextApiRequest, NextApiResponse } from "next";

import slugify from "@sindresorhus/slugify";
import { S3Store } from "@tus/s3-store";
import { Server } from "@tus/server";
import { getServerSession } from "next-auth/next";
import path from "node:path";

import { newId } from "@/lib/id-helper";

import { authOptions } from "../../auth/[...nextauth]";

export const config = {
  api: {
    bodyParser: false,
  },
};

const tusServer = new Server({
  // `path` needs to match the route declared by the next file router
  path: "/api/file/tus",
  datastore: new S3Store({
    partSize: 8 * 1024 * 1024, // each uploaded part will have ~8MiB,
    s3ClientConfig: {
      bucket: process.env.NEXT_PRIVATE_UPLOAD_BUCKET as string,
      region: process.env.NEXT_PRIVATE_UPLOAD_REGION as string,
      credentials: {
        accessKeyId: process.env.NEXT_PRIVATE_UPLOAD_ACCESS_KEY_ID as string,
        secretAccessKey: process.env
          .NEXT_PRIVATE_UPLOAD_SECRET_ACCESS_KEY as string,
      },
    },
  }),
  namingFunction(req, metadata) {
    const { teamId, fileName } = metadata as {
      teamId: string;
      fileName: string;
    };
    const docId = newId("doc");
    const { name, ext } = path.parse(fileName);
    const newName = `${teamId}/${docId}/${slugify(name)}${ext}`;
    return newName;
  },
  generateUrl(req, { proto, host, path, id }) {
    // Encode the ID to be URL safe
    id = Buffer.from(id, "utf-8").toString("base64url");
    return `${proto}://${host}${path}/${id}`;
  },
  getFileIdFromRequest(req) {
    // Extract the ID from the URL
    const id = (req.url as string).split("/api/file/tus/")[1];
    return Buffer.from(id, "base64url").toString("utf-8");
  },
});

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  // Get the session
  const session = getServerSession(req, res, authOptions);
  if (!session) {
    return res.status(401).json({ message: "Unauthorized" });
  }

  return tusServer.handle(req, res);
}

Everything works well if the file is less than the chunk size I specified in the tus.Upload from tus-js-client implementation. However, if that exceeds then @tus/server generates a new URL for subsequent chunk uploads using the generateUrl function.
For whatever reason, the proto value returns http instead of https. This leads to an insecure URL and my application refuses to execute it, throwing CORS errors.


I fixed it by modifying the return statement of generateUrl and hardcoding a s after proto.

...
generateUrl(req, { proto, host, path, id }) {
    // Encode the ID to be URL safe
    id = Buffer.from(id, "utf-8").toString("base64url");
    return `${proto}s://${host}${path}/${id}`;
  },
...

Expected behavior

proto should be https not http

Actual behavior

proto is http not https

Hi, you checked the checkbox indicating you searched issues and find nothing relevant. The most recent issue that was openend before yours, with almost the same title, has your answer: #634 (which in turn was a duplicate of another of the same).

Regarding chunkSize, you should never set it on the client unless you are forced too. See the warnings in the tus-js-client docs if you're wondering why.

mfts commented

Thanks @Murderlon. I swear I searched the issues but must have forgotten to look in closed issues. My bad.

Regarding chunkSize, you should never set it on the client unless you are forced too. See the warnings in the tus-js-client docs if you're wondering why.

Yes, that's a great point. I'm deploying to a serverless infra, therefore my request body size is limited to 4.5 MB hence the chunkSize in the tus-js-client.