Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ DISCORD_WEBHOOK_URL=
# Currency rate provider, currently supported: 'frankfurter' (default), 'openexchangerates' and 'nbp'. See Readme for details.
CURRENCY_RATE_PROVIDER=frankfurter

# Maximum receipt upload size in MB (used by both client validation and server upload limit)
UPLOAD_MAX_FILE_SIZE_MB=10

# Open Exchange Rates App ID
OPEN_EXCHANGE_RATES_APP_ID=
#********* END OF OPTIONAL ENV VARS *********
3 changes: 2 additions & 1 deletion .oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
"func-names": "off",
"prefer-destructuring": "off",
"max-statements": "off",
"jsx-max-depth": "off"
"jsx-max-depth": "off",
"no-nodejs-modules": "off"
},
"overrides": [
{
Expand Down
1 change: 1 addition & 0 deletions docs/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ At least one provider must be configured. SplitPro does not support username/pas
- `DEFAULT_HOMEPAGE`: Sets the landing page route, e.g. `/home` or `/balances`.
- `ENABLE_SENDING_INVITES`: Enable email invites (requires SMTP config).
- `DISABLE_EMAIL_SIGNUP`: Disable email magic-link signup for new users.
- `UPLOAD_MAX_FILE_SIZE_MB`: Maximum receipt upload size in MB. Used by both client-side pre-check and server-side upload limit. Default: `10`.

## Optional variables

Expand Down
8 changes: 5 additions & 3 deletions src/components/AddExpense/UploadFile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React, { useState } from 'react';
import { toast } from 'sonner';
import { useTranslation } from 'next-i18next';

import { FILE_SIZE_LIMIT } from '~/lib/constants';
import { env } from '~/env';
import { useAddExpenseStore } from '~/store/addStore';

import { Input } from '../ui/input';
Expand All @@ -24,8 +24,10 @@ export const UploadFile: React.FC = () => {
return;
}

if (file.size > FILE_SIZE_LIMIT) {
toast.error(`${t('errors.less_than')} ${FILE_SIZE_LIMIT / 1024 / 1024}MB`);
const fileSizeLimit = env.NEXT_PUBLIC_UPLOAD_MAX_FILE_SIZE_MB * 1024 * 1024;

if (file.size > fileSizeLimit) {
toast.error(`${t('errors.less_than')} ${env.NEXT_PUBLIC_UPLOAD_MAX_FILE_SIZE_MB}MB`);
return;
}

Expand Down
14 changes: 11 additions & 3 deletions src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export const env = createEnv({
OIDC_CLIENT_SECRET: z.string().optional(),
OIDC_WELL_KNOWN_URL: z.string().optional(),
OIDC_ALLOW_DANGEROUS_EMAIL_LINKING: z.boolean().optional(),
UPLOAD_MAX_FILE_SIZE_MB: z.coerce.number().int().positive().default(10),
},

/**
Expand All @@ -80,6 +81,7 @@ export const env = createEnv({
client: {
NEXT_PUBLIC_FRANKFURTER_USED: z.boolean().default(false),
NEXT_PUBLIC_IS_CLOUD_DEPLOYMENT: z.boolean().default(false),
NEXT_PUBLIC_UPLOAD_MAX_FILE_SIZE_MB: z.coerce.number().int().positive().default(10),
NEXT_PUBLIC_VERSION: z.string().optional(),
},

Expand All @@ -92,7 +94,7 @@ export const env = createEnv({
process.env.DATABASE_URL ??
`postgresql://${process.env.POSTGRES_USER}:${process.env.POSTGRES_PASSWORD}@${process.env.POSTGRES_HOST}:${process.env.POSTGRES_PORT}`,
NODE_ENV: process.env.NODE_ENV,
DOCKER_OUTPUT: !!process.env.DOCKER_OUTPUT,
DOCKER_OUTPUT: Boolean(process.env.DOCKER_OUTPUT),
NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
NEXTAUTH_URL: process.env.NEXTAUTH_URL,
NEXTAUTH_URL_INTERNAL: process.env.NEXTAUTH_URL_INTERNAL ?? process.env.NEXTAUTH_URL,
Expand Down Expand Up @@ -135,16 +137,22 @@ export const env = createEnv({
OIDC_CLIENT_ID: process.env.OIDC_CLIENT_ID,
OIDC_CLIENT_SECRET: process.env.OIDC_CLIENT_SECRET,
OIDC_WELL_KNOWN_URL: process.env.OIDC_WELL_KNOWN_URL,
OIDC_ALLOW_DANGEROUS_EMAIL_LINKING: !!process.env.OIDC_ALLOW_DANGEROUS_EMAIL_LINKING,
OIDC_ALLOW_DANGEROUS_EMAIL_LINKING: Boolean(process.env.OIDC_ALLOW_DANGEROUS_EMAIL_LINKING),
NEXT_PUBLIC_FRANKFURTER_USED: process.env.CURRENCY_RATE_PROVIDER === 'frankfurter',
NEXT_PUBLIC_IS_CLOUD_DEPLOYMENT: process.env.NEXTAUTH_URL?.includes('splitpro.app') ?? false,
NEXT_PUBLIC_UPLOAD_MAX_FILE_SIZE_MB: process.env.UPLOAD_MAX_FILE_SIZE_MB
? Number(process.env.UPLOAD_MAX_FILE_SIZE_MB)
: 10,
UPLOAD_MAX_FILE_SIZE_MB: process.env.UPLOAD_MAX_FILE_SIZE_MB
? Number(process.env.UPLOAD_MAX_FILE_SIZE_MB)
: 10,
NEXT_PUBLIC_VERSION: process.env.APP_VERSION,
},
/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially
* useful for Docker builds.
*/
skipValidation: !!process.env.SKIP_ENV_VALIDATION,
skipValidation: Boolean(process.env.SKIP_ENV_VALIDATION),
/**
* Makes it so that empty strings are treated as undefined. `SOME_VAR: z.string()` and
* `SOME_VAR=''` will throw an error.
Expand Down
1 change: 0 additions & 1 deletion src/lib/constants.ts

This file was deleted.

11 changes: 6 additions & 5 deletions src/pages/api/upload.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { randomUUID } from 'crypto';
import { randomUUID } from 'node:crypto';
import fs from 'node:fs/promises';
import path from 'path';
import path from 'node:path';
import type { NextApiRequest, NextApiResponse } from 'next';
import { getServerSession } from 'next-auth/next';
import sharp from 'sharp';

import { authOptions } from '~/server/auth';
import { env } from '~/env';

import formidable from 'formidable';
import { type File, formidable } from 'formidable';
import { fileExists } from '~/utils/file';

export const config = {
Expand All @@ -34,10 +35,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)

const form = formidable({
keepExtensions: true,
maxFileSize: 10 * 1024 * 1024,
maxFileSize: env.UPLOAD_MAX_FILE_SIZE_MB * 1024 * 1024,
});

let uploadedFile: formidable.File | undefined;
let uploadedFile: File | undefined;

try {
const [, files] = await form.parse(req);
Expand Down
Loading