diff --git a/.changeset/purple-vans-act.md b/.changeset/purple-vans-act.md new file mode 100644 index 000000000..405236751 --- /dev/null +++ b/.changeset/purple-vans-act.md @@ -0,0 +1,5 @@ +--- +"@uppy/companion": patch +--- + +Reduce companion redis key timeouts to 10 min - In theory this shouldn't affect users diff --git a/Dockerfile b/Dockerfile index 3d7cbc3ff..1dc0bfcce 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:22.18.0-alpine AS build +FROM node:22.22.1-alpine AS build # Create link to node on amd64 so that corepack can find it RUN if [ "$(uname -m)" == "aarch64" ]; then mkdir -p /usr/local/sbin/ && ln -s /usr/local/bin/node /usr/local/sbin/node; fi @@ -7,17 +7,19 @@ WORKDIR /app COPY . /app/ -RUN apk --update add --virtual native-dep \ - make gcc g++ python3 libgcc libstdc++ git && \ +# Ensure corepack is enabled (available in official Node images) and +# install only build-time dependencies using a named virtual package. +RUN corepack enable && \ + apk add --no-cache --virtual .build-deps build-base python3 libgcc libstdc++ git && \ (cd /app && corepack yarn workspaces focus @uppy/companion) && \ - apk del native-dep + apk del .build-deps RUN cd /app && corepack yarn workspace @uppy/companion build # Now remove all non-prod dependencies for a leaner image RUN cd /app && corepack yarn workspaces focus @uppy/companion --production -FROM node:22.18.0-alpine +FROM node:22.22.1-alpine WORKDIR /app diff --git a/packages/@uppy/companion/src/server/Uploader.ts b/packages/@uppy/companion/src/server/Uploader.ts index fb4e3cea7..d611475a6 100644 --- a/packages/@uppy/companion/src/server/Uploader.ts +++ b/packages/@uppy/companion/src/server/Uploader.ts @@ -602,8 +602,11 @@ export default class Uploader { saveState(state: { action: string; payload: unknown }): void { if (!this.storage) return // make sure the keys get cleaned up. + // We don't need more than 10 minutes because progress events should make sure that it doesn't expire before the upload is done. + // assume that after the upload is done, we don't need it around for long // https://github.com/transloadit/uppy/issues/3748 - const keyExpirySec = 60 * 60 * 24 + // https://github.com/transloadit/api2/pull/8345#pullrequestreview-4552806932 + const keyExpirySec = 60 * 10 const redisKey = `${Uploader.STORAGE_PREFIX}:${this.token}` this.storage.set(redisKey, jsonStringify(state), 'EX', keyExpirySec) } diff --git a/packages/@uppy/companion/src/server/helpers/jwt.ts b/packages/@uppy/companion/src/server/helpers/jwt.ts index 18b30c892..c6540a53c 100644 --- a/packages/@uppy/companion/src/server/helpers/jwt.ts +++ b/packages/@uppy/companion/src/server/helpers/jwt.ts @@ -108,7 +108,7 @@ function getCommonCookieOptions({ return cookieOptions } -const getCookieName = (oauthProvider: string): string => +export const getCookieName = (oauthProvider: string): string => `uppyAuthToken--${oauthProvider}` const addToCookies = ({ diff --git a/packages/@uppy/companion/src/server/middlewares.ts b/packages/@uppy/companion/src/server/middlewares.ts index 92def8aee..3e0a0fb26 100644 --- a/packages/@uppy/companion/src/server/middlewares.ts +++ b/packages/@uppy/companion/src/server/middlewares.ts @@ -6,6 +6,7 @@ import packageJson from '../../package.json' with { type: 'json' } import type { CompanionRuntimeOptions } from '../types/companion-options.js' import type { ProviderUserSession } from '../types/express.js' import * as tokenService from './helpers/jwt.js' +import { getCookieName } from './helpers/jwt.js' import { getURLBuilder } from './helpers/utils.js' import * as logger from './logger.js' import { isOAuthProvider } from './provider/Provider.js' @@ -175,7 +176,7 @@ export const cookieAuthToken: RequestHandler = (req, res, next) => { if (oauthProvider == null || oauthProvider.length === 0) { return next() } - req.companion.authToken = req.cookies[`uppyAuthToken--${oauthProvider}`] + req.companion.authToken = req.cookies[getCookieName(oauthProvider)] return next() } diff --git a/packages/@uppy/companion/src/standalone/index.ts b/packages/@uppy/companion/src/standalone/index.ts index 7a48c9689..fa3c4ed80 100644 --- a/packages/@uppy/companion/src/standalone/index.ts +++ b/packages/@uppy/companion/src/standalone/index.ts @@ -136,13 +136,21 @@ export default function server(inputCompanionOptions?: CompanionInitOptions) { }) } - if (process.env['COMPANION_COOKIE_DOMAIN']) { - sessionOptions.cookie = { - domain: process.env['COMPANION_COOKIE_DOMAIN'], - maxAge: 24 * 60 * 60 * 1000, // 1 day - } + const cookieOptions: SessionOptions['cookie'] = { + // AFAIK sessions are only used for the initial oauth2 dance, and not after that. + // Therefore 10 minutes should be plenty of time for the user to complete the oauth2 dance. + // we might want to see if we can make grant work without sessions, so we can remove sessions: + // https://github.com/transloadit/uppy/issues/4394 + // https://github.com/transloadit/api2/pull/8345#pullrequestreview-4552806932 + maxAge: 10 * 60 * 1000, } + if (process.env['COMPANION_COOKIE_DOMAIN']) { + cookieOptions.domain = process.env['COMPANION_COOKIE_DOMAIN'] + } + + sessionOptions.cookie = cookieOptions + // Session is used for grant redirects, so that we don't need to expose secret tokens in URLs // See https://github.com/transloadit/uppy/pull/1668 // https://github.com/transloadit/uppy/issues/3538#issuecomment-1069232909