feat: custom S3 endpoint to use third party storage services (#2133)

Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
This commit is contained in:
Sebastian Goscinski
2024-02-27 11:53:00 +01:00
committed by GitHub
parent 47ec19b46d
commit 5acdf018d3
5 changed files with 39 additions and 7 deletions

View File

@@ -56,6 +56,19 @@ SMTP_PASSWORD=smtpPassword
# Uncomment the variables you would like to use and customize the values.
##############
# S3 STORAGE #
##############
# S3 Storage is required for the file uplaod in serverless environments like Vercel
S3_ACCESS_KEY=
S3_SECRET_KEY=
S3_REGION=
S3_BUCKET_NAME=
# Configure a third party S3 compatible storage service endpoint like StorJ leave empty if you use Amazon S3
# e.g., https://gateway.storjshare.io
S3_ENDPOINT_URL=
#####################
# Disable Features #
#####################

View File

@@ -87,6 +87,7 @@ export const ONBOARDING_DISABLED = env.ONBOARDING_DISABLED;
export const S3_ACCESS_KEY = env.S3_ACCESS_KEY;
export const S3_SECRET_KEY = env.S3_SECRET_KEY;
export const S3_REGION = env.S3_REGION;
export const S3_ENDPOINT_URL = env.S3_ENDPOINT_URL;
export const S3_BUCKET_NAME = env.S3_BUCKET_NAME;
export const UPLOADS_DIR = "./uploads";
export const MAX_SIZES = {

View File

@@ -61,6 +61,7 @@ export const env = createEnv({
S3_BUCKET_NAME: z.string().optional(),
S3_REGION: z.string().optional(),
S3_SECRET_KEY: z.string().optional(),
S3_ENDPOINT_URL: z.string().optional(),
SHORT_URL_BASE: z.string().url().optional().or(z.string().length(0)),
SIGNUP_DISABLED: z.enum(["1", "0"]).optional(),
SMTP_HOST: z.string().min(1).optional(),
@@ -156,6 +157,7 @@ export const env = createEnv({
S3_BUCKET_NAME: process.env.S3_BUCKET_NAME,
S3_REGION: process.env.S3_REGION,
S3_SECRET_KEY: process.env.S3_SECRET_KEY,
S3_ENDPOINT_URL: process.env.S3_ENDPOINT_URL,
SHORT_URL_BASE: process.env.SHORT_URL_BASE,
SIGNUP_DISABLED: process.env.SIGNUP_DISABLED,
SMTP_HOST: process.env.SMTP_HOST,

View File

@@ -20,8 +20,11 @@ import { TAccessType } from "@formbricks/types/storage";
import {
IS_S3_CONFIGURED,
MAX_SIZES,
S3_ACCESS_KEY,
S3_BUCKET_NAME,
S3_ENDPOINT_URL,
S3_REGION,
S3_SECRET_KEY,
UPLOADS_DIR,
WEBAPP_URL,
} from "../constants";
@@ -30,14 +33,21 @@ import { env } from "../env";
import { storageCache } from "./cache";
// S3Client Singleton
let s3ClientInstance: S3Client | null = null;
export const s3Client = new S3Client({
credentials: {
accessKeyId: env.S3_ACCESS_KEY!,
secretAccessKey: env.S3_SECRET_KEY!,
},
region: S3_REGION!,
});
export const getS3Client = () => {
if (!s3ClientInstance) {
s3ClientInstance = new S3Client({
credentials: {
accessKeyId: S3_ACCESS_KEY!,
secretAccessKey: S3_SECRET_KEY!,
},
region: S3_REGION,
endpoint: S3_ENDPOINT_URL,
});
}
return s3ClientInstance;
};
const ensureDirectoryExists = async (dirPath: string) => {
try {
@@ -85,6 +95,7 @@ const getS3SignedUrl = async (fileKey: string): Promise<string> => {
});
try {
const s3Client = getS3Client();
return await getSignedUrl(s3Client, getObjectCommand, { expiresIn });
} catch (err) {
throw err;
@@ -239,6 +250,7 @@ export const getS3UploadSignedUrl = async (
const postConditions: PresignedPostOptions["Conditions"] = [["content-length-range", 0, maxSize]];
try {
const s3Client = getS3Client();
const { fields, url } = await createPresignedPost(s3Client, {
Expires: 10 * 60, // 10 minutes
Bucket: env.S3_BUCKET_NAME!,
@@ -309,6 +321,7 @@ export const putFile = async (
};
const command = new PutObjectCommand(input);
const s3Client = getS3Client();
await s3Client.send(command);
return { success: true, message: "File uploaded" };
}
@@ -358,6 +371,7 @@ export const deleteS3File = async (fileKey: string) => {
});
try {
const s3Client = getS3Client();
await s3Client.send(deleteObjectCommand);
} catch (err) {
throw err;
@@ -367,6 +381,7 @@ export const deleteS3File = async (fileKey: string) => {
export const deleteS3FilesByEnvironmentId = async (environmentId: string) => {
try {
// List all objects in the bucket with the prefix of environmentId
const s3Client = getS3Client();
const listObjectsOutput = await s3Client.send(
new ListObjectsCommand({
Bucket: S3_BUCKET_NAME,

View File

@@ -119,6 +119,7 @@
"S3_SECRET_KEY",
"S3_REGION",
"S3_BUCKET_NAME",
"S3_ENDPOINT_URL",
"SENTRY_DSN",
"SHORT_URL_BASE",
"SIGNUP_DISABLED",