feat(server): add S3_DISABLE_CHECKSUMS option for Cloudflare R2 compatibility

Co-authored-by: danielalves96 <62755605+danielalves96@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-12-10 16:55:19 +00:00
parent 2e5537f3c6
commit ad400bc6fa
5 changed files with 8 additions and 2 deletions

View File

@ -15,4 +15,5 @@ DATABASE_URL="file:./palmr.db"
# S3_BUCKET_NAME=
# S3_FORCE_PATH_STYLE=
# S3_REJECT_UNAUTHORIZED=true # Set to false to disable strict SSL certificate validation for self-signed certificates (optional, defaults to true)
# S3_DISABLE_CHECKSUMS=false # Set to true to disable automatic checksums for S3-compatible services that don't support them (e.g., Cloudflare R2) (optional, defaults to false)
# PRESIGNED_URL_EXPIRATION=3600 # Duration in seconds for presigned URL expiration (optional, defaults to 3600 seconds / 1 hour)

View File

@ -60,6 +60,7 @@ export const storageConfig: StorageConfig = (internalStorageConfig as StorageCon
region: env.S3_REGION || "",
bucketName: env.S3_BUCKET_NAME || "",
forcePathStyle: env.S3_FORCE_PATH_STYLE === "true",
disableChecksums: env.S3_DISABLE_CHECKSUMS === "true",
};
if (storageConfig.useSSL && env.S3_REJECT_UNAUTHORIZED === "false") {
@ -91,6 +92,8 @@ export const s3Client = hasValidConfig
requestHandler: {
requestTimeout: 300000, // 5 minutes timeout for S3 operations
},
// Disable automatic checksums when configured (e.g., for Cloudflare R2 compatibility)
requestChecksumCalculation: storageConfig.disableChecksums ? "WHEN_REQUIRED" : "WHEN_SUPPORTED",
})
: null;
@ -145,5 +148,7 @@ export function createPublicS3Client(): S3Client | null {
requestHandler: {
requestTimeout: 300000, // 5 minutes timeout for S3 operations
},
// Disable automatic checksums when configured (e.g., for Cloudflare R2 compatibility)
requestChecksumCalculation: storageConfig.disableChecksums ? "WHEN_REQUIRED" : "WHEN_SUPPORTED",
});
}

View File

@ -12,6 +12,7 @@ const envSchema = z.object({
S3_BUCKET_NAME: z.string().optional(),
S3_FORCE_PATH_STYLE: z.union([z.literal("true"), z.literal("false")]).default("false"),
S3_REJECT_UNAUTHORIZED: z.union([z.literal("true"), z.literal("false")]).default("true"),
S3_DISABLE_CHECKSUMS: z.union([z.literal("true"), z.literal("false")]).default("false"),
// Legacy encryption vars (kept for backward compatibility but not used with S3/Garage)
ENCRYPTION_KEY: z.string().optional(),

View File

@ -92,7 +92,6 @@ export class S3StorageProvider implements StorageProvider {
return await getSignedUrl(client, command, {
expiresIn: expires,
unsignableHeaders: new Set(["x-amz-checksum-crc32"]),
});
}
@ -221,7 +220,6 @@ export class S3StorageProvider implements StorageProvider {
const url = await getSignedUrl(client, command, {
expiresIn: expires,
unsignableHeaders: new Set(["x-amz-checksum-crc32"]),
});
return url;
}

View File

@ -25,4 +25,5 @@ export interface StorageConfig {
region: string;
bucketName: string;
forcePathStyle?: boolean;
disableChecksums?: boolean;
}